How to organize a drawer the right way
Or let’s talk about cohesion
TL;DR To make a system cohesive, you must ensure that the parts that go together are close to one another.
I sometimes find that the cohesion (and coupling) concept is often considered way too academic, and developers tend to talk about other well-known concepts, such as DRY, YAGNI, KISS, and SRP. The list is long, and I can continue with more acronyms all day 😂 So, I’ve chosen to challenge myself and simplify it.
I hope I succeeded.
Have you decided to continue reading?
Let’s talk about why it’s crucial or, in Kent Beck’s words:
You wanna strive for higher cohesion which reduces the coupling and complexity of the systems. What 😱? Let’s be formal for a moment:
Cohesion is the degree to which the elements inside a module belong together.
Coupling is the degree of interdependence between software modules.
Now it’s time for an analogy. Imagine you’re in the kitchen, it’s cold outside, and you wanna make a hot choco, so you open the silverware drawer, and it’s a total mess. Not only will it be hard to organize, but it’s not clear what belongs where and how to find it.
On the contrary, when everything is in its place, you can easily find a knife if needed or store a new spoon. In my eyes, that’s cohesion, lowering the general mess.
The terms cohesion and coupling are tightly related. They are often considered opposites, which isn’t accurate. Coupling is about connections; cohesion is about belonging together. The challenge is that cohesion is discovered in a context and cannot be created initially, meaning — you keep refactoring your code to keep objects in context.
The ideal scenario (also visible in the picture above) is when objects are arranged by functionality, or in other words, in a domain-driven context. When done correctly, it will result in loose coupling (there is no direct connection between a fork and knife besides the fact they are kitchenware).
Now… if you’ve reached this point, some code examples can be helpful. Let’s start with coupling:
When running the snippet above, the output is ID is null.
You can run it yourself:
So what’s going on? Each of the validity checks is being bypassed since Student
and School
classes are tightly coupled in such a way that School
has intimate knowledge of Student
’s internals and can set its data members. This design could be better. A quick solution will be declaring studentId
with private access, forcing other classes to call the public getter
and setter
methods to access it, as follows:
In this case, the output is :
You can't initialize studentId to a null
ID is not initialized
But how does all of that relate to cohesion 🤷🏻♂️ ?
Let’s get back to the Student
and School
example. If a class does all the work at once (God object), it results from high cohesion (and high coupling). Basically, there is a strong connection between the object in the same context.
While trying to adhere to the single responsibility (or separation of concerns) principle, the interface should be broken into several classes, each targeting different functionality (domain-driven), making it easier to maintain and update.
Conclusion
Simply put, cohesion means that a class should represent a single concept. However, remember that achieving full decoupling is only possible with damaging cohesion and vice versa.
A system architecture that is easy to understand, easy to change, easy to maintain, and to test, is characterized by high cohesion and loose coupling. This combination contributes to the reduction of accidental complexity and enables the creation of well-defined modules.
Ultimately, I want readers to take away that following those principles leads to a system that is easier to maintain and refactor in the future. This is where the actual value lies, and that’s why you should care about cohesion.