Pure functions are one of the main concepts in functional programming. Pure means that it does not depend on the state of the program: non-local variables, reference arguments, static variables, data in external sources like database and also does not modify neither mentioned variables nor parameters provided. Thus, it will always return the same value for the parameters given without causing side effects.
What does it mean for you?
Pure functions are easy to test – just provide them arguments and check the result.
They are easy to debug – just give them parameters and check what happens inside.
They are loosely coupled – changes in the rest of the code will not affect them.
They are predictable and reliable – in case you provide them reference variables, it will not change them.
They go easily with SRP – with such constraints it’s hard to make them do more than one thing.
Strive to write pure functions when possible and reasonable or at least use one of the concepts they follow.
Be especially careful when functions alter the parameters they were provided with, and it’s not obvious why and how they alter them. For example, some implementations of the CQRS pattern introduce query objects with a “Result” field. These query objects are passed to the executors. Executors get the data, and the assign previously null
“Result” with data returned. It’s the change of the passed parameter we can expect.
But I’ve seen a function named getTemplate
which changed the only reference object passed to it. Why is it wrong? Not only do you need to detect that a function supposed to just return the template, alters your data. You also need to handle such situation as well. You can do it either by:
- asking someone who wrote that code to refactor it
- refactoring the function yourself, so it doesn’t alter the data, and returns a copy of the object given (the way it should be from the start – pure function)
- creating a copy of the object before calling a function (so you don’t lose your data), rewriting the data afterward… and leaving the code even messier: with two, very similar, objects existing in the codebase just to preserve the data for a while
Each of this approaches requires rerunning tests or verifying the correctness of such refactor by hand.