paint-brush
Functional data validation in Swiftby@PallasR
2,683 reads
2,683 reads

Functional data validation in Swift

by Ricardo PallásSeptember 20th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

I am going to talk about a little library I created in Swift to be used either standlone or with <a href="https://github.com/typelift/Swiftz" target="_blank">Swiftz</a> lib. It is called <a href="https://github.com/RPallas92/Swiftz-Validation" target="_blank"><strong>Swiftz-Validation.</strong></a>

Company Mentioned

Mention Thumbnail
featured image - Functional data validation in Swift
Ricardo Pallás HackerNoon profile picture

I am going to talk about a little library I created in Swift to be used either standlone or with Swiftz lib. It is called Swiftz-Validation.

What is Swiftz-Validation?

It’s a data structure that typically models form validations, and other scenarios where you want to aggregate all failures, rather than short-circuit if an error happens (for which Swiftx’s Either is better suited). A Validation may either be a Success(value), which contains a successful value, or a Failure(value), which contains an error.

A Validation is a data structure that implements the Applicative interface (.ap), and does so in a way that if a failure is applied to another failure, then it results in a new validation that contains the failures of both validations. In other words, Validation is a data structure made for errors that can be aggregated, and it makes sense in the contexts of things like form validations, where you want to display to the user all of the fields that failed the validation rather than just stopping at the first failure.

Validations can’t be as easily used for sequencing operations because the.ap method takes two validations, so the operations that create them must have been executed already. While it is possible to use Validations in a sequential manner, it's better to leave the job to Either, a data structure made for that.

Validating data example

In the following example we are going to validate a password: it should contain more than 8 characters, it should contain an especial character and it has to be different from the user name.

Advantages of using Swiftz-Validation

Things like form and schema validation are pretty common in programming, but we end up either using branching or designing very specific solutions for each case.

With branching, I mean using if-else conditions, things get quickly out of hand, it doesn’t scale because it’s difficult to abstract over it and it’s hard to reason about each rule. Let’s see an example of the same validation as before, using branching:

Because this function uses if conditions and modifies a local variable it's not very modular. This means it's not possible to split these checks in smaller pieces that can be entirely understood by themselves — they modify something, and so you have to understand how they modify that thing, in which context, etc. For very simple things it's not too bad, but as complexity grows it becomes unmanageable.

Advantages

The main advantages of Swiftz-Validation is that:

  • Easy to understand and reason about each validation in its own
  • Easy to compose validation rules
  • Easy to reuse validation rules and compose more complex validations (DRY principle)
  • It has a well know interface or abstraction to work with (It is a functor, pointed, applicative and a semigroup). So you can combine validations with sconcat (Semigroup), apply functions with ap (Applicative), transform results with fmap (Functor) and react to results with some kind of pattern matching with a switch statement.

In the following example, you can see how the Validation structure gives you a tool for basing validation libraris and functions on in a way that’s reusable (DRY) and composable:

How to use the library

The Validation lib is implemented as an enum with two cases:

  • Success(successValue) — represents a successful value.
  • Failure(failureValue) — represents an unsuccessful value.

Validation functions just return one of these two cases instead of throwing errors or mutating other variables. The keys of working with Validations are:

  • Combining validations: sometimes we want to create very complex validation rules. They key is to create simple reusable and composable validations in ther own and combine them into a complex validation structure.
  • Transforming validations values: Sometimes we get a Validation value that is not what we are looking for. We don't really want to change anything about the status of the validation (whether it passed or failed), but we'd like to tweak the value a little bit. This is the equivalent of applying functions in an expression.
  • Reacting to validations results: Once we have the validation results, we need a way to react accordingly if the value is a success or a failure.

Now, we are going to see some examples:

Combining validations

Transforming validation values

Reacting to validation results

Conclusion

I wrote this lib as an personal experiment since the core SwiftZ library doesn’t include a similar data structure and I think it is a very important one, because validation is pretty common in every sowftware program. The lib is still work in progress but it can be used with SwiftZ or standalone. I would add more operations like liftA3 and similar.

Feel free to pull request the repo and improve it, thanks!.

The lib it’s inspired by the Validation Package for Haskell: https://hackage.haskell.org/package/Validation

Acknowledgements

  • Thanks to Jose Luis Alcala for helping me with Swift and SwiftZ.
  • Thanks to @jlopez_rz for helping me with test cases.
  • Thanks to Jorge Aznar for helping me writing this article.