Any software project should not only consist of so-called ‘clean code’ but should also have a clean architecture. What does it mean to have a clean architecture? Over the years there have been many ideas about this, which may differ in their details, but are all based on the same principles. The most important objective is the separation of concerns. This is achieved by dividing software into layers to achieve loose coupling and high cohesion.
Most software evolves over time. If we want to upgrade our software with a snazzy new front-end, a faster database or an easy-to-use framework, parts of the software will have to be replaced. To enable this, software should be designed in such a way that it supports such replacements by requiring minimal changes, by making sure that each of the components has (or makes use of) little or no knowledge of the definitions of other separate components. This is called loose coupling.
Many integrated products, such as laptops or tablets, are good examples of tight coupling: if your laptop screen breaks, you’re probably better off buying a new laptop. Because the screen is fixed to the laptop and won't come loose, it makes replacing the screen very expensive. A loosely coupled computer would allow effortlessly changing the screen, which is the case for a desktop.
So, if we want to achieve loose coupling, the code should be written as generic as possible and only go into specifics whenever unavoidable. For instance, if we want to swap out a database for a new one, this should not affect the functionality of the code, but should only affect the class that is dedicated to connecting to the database.
Cohesion in software engineering is the degree to which the elements of a certain module (or class) belong together. Low cohesion (or coincidental cohesion) is when parts of a module are grouped arbitrarily, whereas high cohesion (or functional cohesion) is when parts of a module all contribute to a single well-defined task of the module.
The Model-View-Controller design pattern is a good example of high cohesion: all methods related to the model are grouped in a model class, all methods relating to displaying the information are grouped in the view class and all methods that are related to processing events are written in the controller class.
The picture shows four quadrants.
Three that are not desired:
- Loose coupling and low cohesion results in a complex system with modules that don’t have a clear task and have poor maintainability.
- Tight coupling and low cohesion results in a monolithic system where modules don’t have one clear purpose but serve various goals.
- Tight coupling and high cohesion results in a dependent system where modules depend on each other and can’t function without each other.
Your goal needs to be: Loose coupling & High cohesion
In software development we strive for loose coupling and high cohesion, because it leads to increased module reusability, better system maintainability and reduced module complexity, making the code easier to understand and debug. From a quality engineering perspective this is the best way to achieve quality at speed (both in development and in operations).