Coupling and Cohesion
Introduction
Coupling and cohesion are two fundamental concepts in software design that help us determine how well the components of a system are organized. Coupling refers to the degree of interdependence between modules, while cohesion refers to the degree to which the elements within a module are related to each other. These forces need to be balanced to create a system that is easy to understand, maintain, and extend.
Coupling vs Cohesion
"Pull the things that are unrelated further apart, and put the things that are related closer together."
-- Kent Beck
Just arbitrarily splitting our system into modules does not produce a well designed system. We need to consider how the pieces fit together and how they will communicate.
Coupling
Coupling refers to the degree of interdependence between modules. It measures how much one module relies on another module. There are many different types of coupling, determined by how the modules are connected, but the exact type is not as important as the degree of coupling. Coupling is spectrum, ranging from low to high:
- Low Coupling: Modules are independent of each other and communicate through well-defined interfaces. Changes in one module have minimal impact on other modules.
- High Coupling: Modules are tightly bound together and changes in one module have far-reaching effects on other modules.
Lower coupling makes system easier to modify because it allows us to understand and change modules in isolation. Higher coupling often results in cascading changes, where a small change in one module requires changes in many other modules.
A system with zero coupling, where modules are completely independent of each other, doesn't do anything. The modules need to work together to achieve a common goal. The goal is to strike the right balance between coupling and cohesion to create a system that is easy to work with.
Types of Coupling
Michael Nygard, author of "Release It!", gives the following model of coupling:
- Operational: A consumer can't run without a provider
- Developmental: Changes in producers and consumers must be coordinated
- Semantic: Change together because of shared concepts
- Functional: Change together because of shared responsibility
- Incidental: Change together for no good reason (e.g., breaking API changes)
Coupling at Scale
The importance of loose coupling increases as the size of the organization grows. A startup with a single team of developers can easily deal with a tightly coupled system. They can all sit in the same room and talk to each other about how the pieces fit together. For these companies creating a tightly coupled monolith is often the fastest way to get a product to market.
Organizations with multiple teams need to be more cautious about coupling. As the number of teams grows, the number of communication paths between them grows exponentially. This makes it difficult for everyone to understand how the pieces fit together. A loosely coupled system allows teams to work on different parts of the system without having to understand how every other part works.
Cohesion
Cohesion refers to the degree to which the elements within a module are related to each other. It measures how well the elements in a module work together to achieve a common goal. Related functionality should be grouped together, while unrelated functionality should be separated. Cohesion is also a spectrum, ranging from low to high:
- Low Cohesion: A module contains unrelated elements that don’t belong together. The elements are not well organized and don’t work together to achieve a common goal.
- High Cohesion: A module contains elements that are closely related and work together to achieve a common goal. The elements are well organized and belong together.
Highly cohesive modules are easier to work with because everything you need to know about a particular piece of functionality is contained in one place. Low cohesion can lead to modules that are difficult to understand and maintain, as unrelated elements are mixed together. We might need to bounce around the codebase just to understand how a single piece of functionality works.
Advantages of Low Coupling
- Improved understandability: Low coupling results in modules that are independent of each other and communicate through well-defined interfaces, making it easier for developers to understand the code and make changes. We can understand and change modules in isolation.
- Better error isolation: Low coupling reduces the likelihood that a change in one part of a module will affect other parts, making it easier to identify and fix errors.
Advantages of High Cohesion
- Improved maintainability: High cohesion results in modules that contain related elements that work together to achieve a common goal, making it easier for developers to understand and maintain the code. Everything you need to know about a particular piece of functionality is contained in one place.
- Better reusability: High cohesion makes it easier to reuse modules in other parts of the system, as they contain well-organized and related elements.
Disadvantages of High Coupling
- Increased complexity: High coupling makes it difficult to understand how the pieces of a system fit together, as changes in one part of the system have far-reaching effects on other parts. This can lead to bugs and errors.
- Reduced maintainability: High coupling makes it difficult to make changes to a system, as changes in one part of the system have far-reaching effects on other parts. This can lead to a system that is difficult to maintain and extend.
Disadvantages of Low Cohesion
- Decreased understandability: Low cohesion makes it difficult to understand how the elements in a module work together to achieve a common goal, as unrelated elements are mixed together. This can lead to a system that is difficult to understand and maintain.
- Reduced reusability: Low cohesion makes it difficult to reuse modules in other parts of the system, as the elements are not well organized and don’t work together to achieve a common goal.