As we mentioned in our previous post, some of us at SB attended ElixirConf EU 2018 in Warsaw, last April. We already covered some of the most interesting topics in the post and here's another one that we think you may enjoy: it's the summary of Georgina McFadyen's talk on SOLID properties in functional languages and Elixir.
It’s not enough to have working code: we need to make it clean, maintainable, testable; in other words apply some design to it. Here’s where SOLID principles came in for OO languages. The question Georgina McFadyen asked in the talk is: could we apply those principles to Elixir (and functional languages more generally)?
The talk was a good refresher on SOLID principles and how to apply them to an Elixir codebase. Wikipedia has extensive definition of all the principles, but here I’m using McFadyen’s shorthands, which were great to get to the core of each principle.
Every module or class should be responsible for a specific part of your system.
Also, “a class should have only one reason to change” — Robert C. Martin
(This still applies to Elixir if we replace “class” with module or function).
However, every module adds overhead in terms of maintenance and testing, so always ensure each module can justify its existence.
Ability to add new code without touching existing code.
An example of this principle is how validation benefits from a plug-in architecture, with a generic rule-checking mechanism and different validation rules, each implemented as a separate module (i.e. a "plug-in rule").
This requires defining a contract for the rules, which can be done with Elixir Behaviours.
The architecture allows us to source rules from a configuration file.
In this architecture, adding validation to a field can be done without touching existing code and testing becomes easier (you can have a config file for test and one for other environments).
In the OO world, the core of the principle is that it should be possible to use the base/parent class in place of any of its subclasses.
Elixir is functional, so it doesn’t rely on inheritance as much as OO languages. However, we can adapt the definition to Behaviours:
Where we have code that expects a generic type (i.e. Behaviour), ensure you are only using function calls defined on that Behaviour.
This really needs to be understood by watching the video: the example can’t be summarised in a few words.
Clients should not depend on contracts they don’t use.
In Elixir, applying this principle would mean splitting large modules or Behaviours.
The original definition is quite complex, but it could be summarised with a couple of statements:
“Separate high- and low-level layers”.
“Depend on abstraction, rather than the details”.
Example: abstract away access to a DB, so it doesn’t matter if under the hood you have a local or remote database, a fake one, or a series of mocks.
The examples presented in the talk were proof that you can apply all the SOLID principles to Elixir and still get idiomatic code. The only ill fit is Liskov’s principle, which is very much rooted in the OO world.
In the case of Elixir, then, McFadyen suggests we could use the acronym SORTID, which would translate to the following principles:
Finally, McFadyen leaves with an open question at the end of the talk. Functional languages are immutable and rely on recursion a lot: should we create some design principles specifically for those?
You can find slides and a video of the talk on the ElixirConf EU website.
Want to know more about what it's like to work in tech at Simply Business? Read about our approach to tech, then check out our current vacancies.Find out more
6th Floor99 Gresham StreetLondonEC2V 7NG
Sol House29 St Katherine's StreetNorthamptonNN1 2QZ
© Copyright 2020 Simply Business. All Rights Reserved. Simply Business is a trading name of Xbridge Limited which is authorised and regulated by the Financial Conduct Authority (Financial Services Registration No: 313348). Xbridge Limited (No: 3967717) has its registered office at 6th Floor, 99 Gresham Street, London, EC2V 7NG.