Cohesion And Coupling Flashcards
Cohesion
Cohesion is the degree to which the elements inside a module belong together. A module could be a class or a package or even a microservice. Simply put, it means “the code that changes together, stays together”.
A module with high cohesion contains elements that are tightly related to each other and united in their purpose. For example, all the methods within a User class should represent the user behavior.
A module is said to have low cohesion if it contains unrelated elements. For example, a User class containing a method on how to validate the email address. User class can be responsible for storing the email address of the user but not for validating it or sending an email: That should belong to some other class like Email.
As you can see, the concept of cohesion is closely related to the Single Responsibility Principle (SRP, one of the SOLID principles) which states that a class should only have one responsibility. The module following the SRP is likely to have high cohesion.
Advantages of High Cohesion
Modules with a single, well-defined purpose are easy to understand and much more readable. The name of such modules clearly announces their purpose and such modules do just that. It helps the reader to build an intuition about what the module is doing without reading every line in the module. Also, there are no surprises while reading the code of such modules.
For example, it would be confusing to the reader if the User class contains the code for validating the email address.
It is easier to make code changes since all the related code is within the module. For example, if a developer has to make changes to the user behavior, they can jump to the User class and make all the changes in one class. This will keep the area of impact limited. Compare this to design where user behavior is spread across multiple classes and each has to be changed to achieve the desired change. It is easier to test the code. Since such modules do not depend on other modules for their purpose, they are easy to unit test. Also, it is easy to build and deploy the changes when they are limited to a single module.
Changes to such modules are less prone to bugs. It is easier to make mistakes when you are making changes across modules.
Finally, they are reusable. Since such modules perform single responsibility, they tend to be used wherever there is such a need.
Overall, highly cohesive modules reflect better quality of software design. Hence, look for elements in a module, that are not directly related to the main purpose. Move them to some other module that better fits the purpose or create a new module.
Coupling
Coupling is the degree of interdependence between software modules. A module could be a class or a package or even a microservice. Effectively, the coupling is about how changing one thing required change in another. Two modules have high coupling (or tight coupling) if they are closely connected. For example, two concrete classes storing references to each other and calling each other’s methods. As shown in the diagram below, Customer and Order are tightly coupled to each other. The Customer is storing the list of all the orders placed by a customer, whereas the Order is storing the reference to the Customer object.
Every time the customer places a new order, we need to add it to the order list present inside the Customer. This seems an unnecessary dependency. Also, Order only needs to know the customer identifier and does need a reference to the Customer object.
Advantages of Low Coupling
Loosely coupled modules are easier to develop and maintain. Since they are independent of each other, we can develop and test them in parallel. Also, they can be modified and updated without affecting each other. We can independently build and deploy such modules, significantly reducing the deployment time.
Tightly coupled modules are difficult to change. The developer needs to understand multiple modules and how they relate to each other. They need to be careful in making changes to all the modules consistently. This makes it more error-prone. Also, we need to build, test and deploy each changed module, further increasing the development effort.
Tightly coupled modules are also difficult to test. Unit testing a single module is difficult since it heavily depends on other modules. Significant effort has to be spent in mocking the calls to other modules so that the module can be independently unit tested.
Integration tests are also difficult to set up. Overall the tests are fragile since a change in any one module could break the tests. Debugging such modules is also complex because it needs all the dependent modules running.
A tightly coupled module is less likely to be reused. Such a module does not perform anything useful on its own. Hence, it rarely fits the purpose for someone else to reuse. Also pulling it as a dependency is difficult since it brings in other dependent modules along with it. Overall loose coupling reflects the higher quality of software design. Hence, we should aim for designing modules that are as independent as possible.
Cohesion vs. Coupling
Cohesion and coupling are related to each other. Each can affect the level of the other.
High cohesion correlates with loose coupling. A module having its elements tightly related to each other and serving a single purpose would sparingly interact and depend on other modules. Thus, will have loose coupling with other modules.
Similarly, the tight coupling could be a sign of low cohesion. Modules could be heavily dependent on each other due to the elements spread across the two modules. And thus, will have low cohesion.