A pragmatic look at functional programming: Abstraction, parallelism and testing (Part 2/3)
In the previous article we covered the immutability orientation. While investigating the advantages of functional programming languages, we also learnt that it offers a much higher level of abstraction. It requires a radical paradigm shift and it can be shocking at first. But hey, moving from imperative to object oriented programming had a learning curve too, and it totally paid off. Writing functions that might take functions as parameters and return different functions isn’t exactly trivial, but once you are a bit fluent with these higher order functions, composition, monads, functors, etc. you will be able to do much more with less. You will find yourself coding in a much more declarative fashion, that is, declaring what you want rather than specifying exactly how to achieve it.
Turns out that once the majority of your code is made of pure functions operating on immutable objects, concurrency poses no risk and parallelism is almost trivial, as opposed to shared mutable state that requires careful synchronisation of critical blocks and explicit forking and joining of threads.
As for testing, in the usual OOP scenario where you have mutable objects that affect each other, you need to mock everything around the object you are testing, set its initial state, set expectations on the mocks, invoke some methods on your object, verify that its final state is correct and that all mock expectations where met, plus make sure that no unexpected side effects were produced. But when you are testing a pure function you only need to feed it some values and verify the result.
In the next article we will share our experience developing a project entirely in Scala.