Safer Programming With Types
Functional programming has been a passion of mine for several years now, increasingly taking a central position in my work since I started building user interfaces with React in 2014.
Sometimes it's hard to articulate why I'm so passionate about this approach. I love learning, so I often wonder if it's purely because it's a massive topic to learn and challenge myself with. Other people think this too, as they struggle to look beyond some of the weird and wonderful terminology (it isn't just arbitrarily made up, I promise!).
Properly reflecting on the reasons I'm passionate about this style of programming reveals some more practical points. Firstly, I'm a huge advocate of testing in professional software development and pure functions make superb fodder for TDD.
Secondly, I find that declaratively building up a program from a kit of well understood, well tested parts is so much better than the spaghetti code so often associated with Object Oriented programming.
Thirdly (lastly?) I find there's a supreme elegance in the way software can be designed using these techniques. As the title of this post suggests, we can use our data types and functions to ensure that we're handling all the potential problems our code may throw at us. Rarely is it the happy path which causes us issues, but instead it is the failure modes and error branches which we don't consider that trip us up.
Safety: the condition of being protected from or unlikely to cause danger, risk, or injury.
Many of the types associated with FP embed this idea of safety into their core. You may have heard of Maybe's, Either's, and Future's (also known as Async) - Algebraic Data Types which help us model disjunction, typically in the form of success or failure.
Their safety comes from forcing us to understand how our computations may fail and providing code to handle those situations. They don't excuse us from understanding the underlying runtime (for example, knowing that
JSON.parse will throw an exception but
parseInt will fail by returning
NaN) but they are often accompanied by many useful library functions which create safer versions of the functions we use daily.
As hinted earlier in the post, this is a big topic with lots of material already available on the internet. I certainly can't do it justice in one post!
I have, however, been giving a talk on this subject (slides below) and created an accompanying workshop. They're both better experience in person, but if you're interested in some of the techniques touched on here, they're definitely worth checking out.
I plan to break out some of the aspects of this talk into specific blog posts focussing on topics such as how to represent the absence of a value, removing the need for try/catch and how to build async software from composable, pure functions. For now, have a read through the slides and have a go at the workshop exercises (if you have any questions then feel free to raise an issue or get in touch via twitter!)