Pure Functions: High Cohesion, Low Coupling

Boost the quality, maintainability, and readability of your code

Ammar Merakli
4 min readAug 21, 2020

TL;DR Why would you bother to write pure functions? Do you need to establish high cohesion and low coupling? Well, if you want clean and high-quality code with easy maintainability, you must. Period.

Photo by ThisisEngineering RAEng on Unsplash

For people who see any of those terms for the first time, it would be better to start with the meanings. Please keep in mind that I will try to explain the concepts from the aspect of Object-Oriented Programming (OOP). What do I mean by that? For instance, I will refer to classes, not modules.

Pure function:

In software engineering, a pure function is a function that has the following two properties:

1. It returns the same value for the same inputs (no variation)

2. Its evaluation has no side effects (It should not change any other variables that are outside of the scope of the function)

I will explain why you need to write pure functions and how it makes unit tests perfect. By the way, it seems like a piece of cake at first glance, but believe me, it is a sneaky one. I saw engineers with many years of experience but still don’t seem to grasp the importance of it.

Cohesion:

In a nutshell, cohesion in software engineering is a measure of the strength of the relationship between the class’s methods and the data themselves.

Cohesion is often contrasted with coupling, a different concept (we will come to that in a bit). High cohesion often correlates with loose coupling and vice versa.

So, low cohesion means that the class does a great variety of actions. In other words, it has different responsibilities, which conflicts with the separation of concerns in software engineering. It is not focused on what it should do. This isn't good. Your class/function should have one specific responsibility. That will increase cohesion.

On the contrary, high cohesion means that the class is focused on what it should be doing, i.e. only methods relating to the intention of the class.

Coupling:

In software engineering, the coupling is the strength of the class relationships. In other words, it refers to how related or dependent two classes are on each other.

Low coupling is often a sign of a well-structured software and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability.

As you can imagine, if your classes are dependent on each other, maintainability will become harder. Because if you change anything in a class, you should check whether the dependent classes are still functioning correctly.

Loosely coupled and highly cohesive code
A single piece of code that does everything

Pure functions and unit testing:

I really would like to dive deep into this part in a separate article. I may in the future, but for now, I will try to explain the benefits of the pure function and its positive effects on unit testing.

We can apply “loose coupling and high cohesion” to function level as well. So function units also must have one responsibility (highly cohesive) and independent on each other (loosely coupled).

As we described above, writing a pure function means giving only one responsibility to the function. It takes a certain amount of inputs, and it has an expected output. And most importantly, it has no side effects.

I will try to give a clear example of how the function should look like:

As you can see, it is easy to unit-test your function. Because you know exactly what your function does. By and btw, I have to say that most of the time, unit testing is mixed with integration testing. People think their tests are unit tests, but in most cases, they are not. So, if you write pure functions, which means your function is not dependent on any other global parameter, unit testing will become super easy out of the box.

Say, for example, if certain circumstances are satisfied, you want to assign a boolean to a global variable. In a bad practice, you would do that assignment in a function that also has other responsibilities:

As you can see here, it is not unit-testable. You can not unit test “someMethod.” You can, of course, think that you can write a unit test for it. But it will end up being an integration test. Because you must test that isGreaterThanTen should be true when certain conditions apply.

Rather, in good practice, you would write a function like this:

As you can see, we wrote a pure function which is called isLessThanTwo. And it is easy to unit test. It has no side effects. Purely does what it should do. Now you don’t have to worry about the global “isSingle” variable. If you unit test the “isLessThanTwo” method, the “isSingle” variable will be covered as well.

A side note: if you embrace Test-Driven-Development it will help you write pure functions.

Conclusion:

As we saw in the examples, writing loosely coupled and highly cohesive code with pure functions will boost your maintainability and code quality. Because now, you have maintainable, fully functional unit tests. If you need to change some stuff in your code, updating both your functions and unit tests will be extremely easy. Your code will be easy to read as well.

PS: I want to thank my colleagues who made me understand the importance of writing pure functions. They know themselves :)

I have spoken. This is the way 🤓

--

--