A framework I wrote (and why you shouldn’t use it)

I was recently shown FluentValidation , a popular framework for object validation in .NET — I decided to re-write the framework in Swift. It works nicely… but should you use it?

Fluent Validation

Here is the original .NET framework (and here is my version). The idea behind the framework is you can use “fluent” rules to validate the properties of an instance so as to determine whether the entire instance can be considered “valid” or not. Suppose you have a CustomerModel such as:

You can simply import FluentValidation and subclass FluentValidator to build a validator for the CustomerModel . It’s entirely strongly typed, thanks to KeyPath constraining the input values of the rules to valid properties of the generic model. In the end, I think the Swift framework came out even more succinct than the .NET one!

I ❤ Generics. Is that a T-Shirt yet?

Then, the validator can be instantiated and re-used:

Pretty neat eh? Thanks to the power of generics, the error returned when a rule fails is strongly typed too. If you prefer to simply use a string message like in the .NET version, you could create an extension on String that makes it conform to the Error protocol…

Do you really need a framework for validation?

Consider the following static function:

It achieves the same task as the validator: given a CustomerModel , an error will be returned if there is something wrong with it. You can do it yourself, without a framework!

Nutritional Value

As Cocoapods wormed their way into normality, there was a shift in the iOS developer’s mindset: with a single line in a [Pod]file, it became possible to import multiple progress spinners that could be instantiated at your whim (you know the library I’m talking about). It also became possible to outsource the development of your entire network layer (again, you know exactly what I’m talking about). But where is the nutritional value? For me, the reason I choose to code is.. well, because I like to code. There is so much you can learn from building your own network layer and improving upon it in your next project. But there are many other reasons why you should think twice before making yourself dependent on a third party.

Convenient, but probably not healthy for you in the long term

Confidence

When working in on a project for a client, there will inevitably be periods where bugs are coming in left, right and centre. The days when lunch is out of the question. The last thing you need during these trying times is to have to answer the question:

Was this bug created by me/my team or a library we use?

Suppose you import my framework and a bug is raised in your app regarding validation not working correctly. Is it my fault, or yours? You might have downloaded my framework manually and ran the unit tests: if you did, you’ll see that I have 40+ passing tests resulting in 100% code coverage. Did you read all the tests individually? If not, how can you be sure that one of passes isn’t a false positive? If you had used a static function for object validation such as the one shown earlier in this article, you can immediately determine that you were responsible for the introduction of the bug.

Sometimes the problem is bugs not occurring when they should. Having the app crash during development is an essential part of discovering that you’ve done something wrong and you need to fix it before you commit your code. I’ve seen a layout framework that simply does nothing if a view doesn’t have a superview: this caused a lot of confusion for us as we didn’t realise we forgot to add the target view to the hierarchy and so we were left wondering what was wrong. By default, Autolayout causes a crash if you attempt to make constraints in an invalid environment — very useful!

Another framework we used in an Objective C project was wrapping all calls to delegate methods in a @try { } block. This meant that all of our code triggered by the callback was not crashing ever, even upon accessing invalid ranges in arrays. Stepping through the code with breakpoints showed a function simply failing to execute some of it’s lines.

Maintenance

This happened at work just before I published this article, so I decided to include a screenshot.

What happens when a new version of Swift is released? I may be too busy to update FluentValidation , so your team may not be able to download the latest version of Xcode in their next sprint. Or perhaps I’ll rename a few methods, resulting in your build failing the next time you update your dependencies. I seem to remember a time when I opened a project from a year earlier and had to replace every .distinctUntilChanged() with .distinctUntilChanged({ $0, $1 }) before I could compile.

Or, even worse, maybe you went to Github and noticed a new commit:

This recently happened to us: a framework we baked into our navigation structure is no longer going to be updated. Good luck to us telling the client about it.

What happens next? You’ll either need to familiarize yourself with my code that I wrote over two weeknights because I wanted to prove a point, or you’ll need to rip FluentValidation out of your app and re-write all your validations.

Onboarding

It’s important to also consider how easily a new developer can jump in to the code and understand what’s going on. Do they need to learn an entirely new paradigm before they can even begin to understand how to implement a feature or fix a bug?

This is… very confronting when you first see it.

Conclusion

Of course, there are cases where third party frameworks are useful. And of course I don’t dislike open source projects: I love sharing knowledge and ideas — that’s why you can read this article for free!

The message to take away from this is: try not to let yourself be enticed to import a framework because it has 15,267 stars on Github or a because it has a fancy logo and shiny badges at the top of it’s ReadMe file. In fact, try not to think of it as “importing a framework” — think of it as “making yourself dependent on a stranger’s code”.

Write the code yourself. Trust the code you wrote. Improve on it next time.

Don’t let the iOS community steers itself towards an npm-esque distaster.