High cohesion, low coupling
Posted on February 15, 2025 • 3 minutes • 520 words
Table of contents
The terms ‘high cohesion’ and ‘low coupling’ cause quite a bit of confusion among developers. While they often mentioned in the scope of microservices, the underlying principles are applicable to any modular software system, including monoliths, distributed systems, and even the modular monoliths (which is just an app, really).
A graphical definition of these terms is simple:
Here the modules B and C are not coupled, whereas the module A is coupled to B as it has a direct dependency on some functionality of B. In the ideal scenario, all modules must be independent of each other. Your application should consist of the glue code only, which should be as concise as possible. The glue code must connect modules using their interfaces only and must never access the inner structure of the modules.
Why Coupling is bad
Changes in the module B will affect both the glue code (which is expected) and the module A. This dependency of A on B makes A actually a part of B, and not a module on its own. Worse, in bigger systems, a small change in a module can cause a cascade of changes in all coupled dependencies.
Why Cohesion is good
The only purpose of the glue code is to provide cohesion between modules. In an ideal design, this code must not provide any functionality of its own. In reality, the glue code often contains some occasional business logic. This logic needs to be extracted into separate modules when it becomes either an important part of the system functionality or the glue code becomes too big.
Why Glue code must be small
The glue code is the most volatile piece of the system. As modules evolve and new ones are added, it must change to accommodate all new requirements. In some cases, due to design changes or optimisations, it may be replaced completely – and therefore the succinct glue code is crucial.
Folding the dimensions
Modules themselves can be the glue code for other independent modules. This way, such a module hides the underlying complexity by exposing only the minimally necessary interfaces. This is an example of collapsing (or folding) a dimension, a technique of reducing the complexity by confining the underlying structure at its one level (dimension) and only allowing the limited interaction with the upper levels.
This process can repeat at multiple levels, creating more and more functional modules with the constrained interfaces.
There must be a catch
I have seen software teams, small and large, that don’t follow this approach. Reasons are many:
- Often teams’ architects have no understanding of the overall structure of the project. This stops them from thinking the solution as modules and glue code.
- And more often than one might think, teams have no architects at all.
- The glue code grows uncontrollably and turns into a ball of mud. Splitting such code into modules resembles untangling the wires from the box of old chargers.
- Microservices and lambdas turned into religion. Just splitting the system into microservices often is considered a virtue that magically solves complexity and scalability problems.
Happy to discuss on Hacker News .