Writing declarative code using Result Extensions

I recently read an excellent post by Benedikt Terhechte where he extends the API of optionals. At Standard Bank, we use the Result Type quite extensively, so I took the same ideas and applied it to the Result Type. After this post we will end up with composable code and a declarative API, something akin to the below snippet.

You can follow with a working example in the following playground file.

A fictional brief

Let’s pretend we are building a simple app for a client. After sitting with the domain expert, he informs us that anyone can browse the app, but to become a registered user you need to fulfil the following requirements:

  • A registered user must have a valid identifier.
  • A registered user needs to have a valid email address and the email address must be a gmail address.
  • A registered user must be either a Millennial or a Generation X.
  • We need to show to the user why they cannot be registered after trying.

Extending the Result Type with an applicative

One of the requirements is to show the user why they cannot become a registered user. By using an applicative, we can achieve this quite beautifully.

Before writing our applicative we need to define a protocol called a semigroup. Brandon Williams has an excellent explanation on what a semigroup is and why we would want to use it. For the purpose of this post, we will only need anArray to conform to the protocol.

We can now write our applicative extending the Result Type.

This allows for the following code to be written.

If you print the contents of the user object above, you will get the following:

failure: 3 elements
- "invalid id"
- "invalid email"
- "invalid millennial"

Stephen Celis has an excellent video detailing the above called Applicatives and Swift. A great watch.

Extending the Result Type with AND

One of the requirements is for a user to have both a valid email address and a valid gmail address. Let’s extend the Result Type with the following code for and.

Now we can do the following.

If you print the result you will get the following output.

failure: 1 element
- "invalid gmail address"

Extending the Result Type with OR

The last requirement is for a user to be either a Millennial or Generation X. We can fulfil this requirement by extending the Result Type with or.

Now we have the following.

If you print the result you will get the following output.

failure: 2 elements
- "invalid millennial"
- "invalid gen x"

Putting everything together

The below snippet satisfies all of our requirements.

If you print the registeredUser, you will either get a successful result depending on our inputs or an output detailing reasons why the user could not be registered. In the case above, the result will print the following.

failure: 4 elements
- "invalid id"
- "invalid gmail address"
- "invalid millennial"
- "invalid gen x"

BONUS

Let’s extend the Result Type with custom operators for and and or.

We can now update our RegisteredUser.create method to the following.

Conclusion

You can achieve a high level of flexibility by having small functions that are easily composed. In the end you have code that is easier to maintain, easier to read, and easier to test.

You can find a working example in the following playground file.

Follow me on twitter, where I regularly like to tweet about fun topics like this.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.