Cohesion is considered important in software design. It is often mentioned how our classes, methods, libraries... should have a high cohesion. I will try to explain cohesion in an illustrative way and give you some of the indicators of high cohesion in software modules.
Cohesion is defined in a dictionary as
the act or state of sticking together tightly.
In computer programming, cohesion refers to the
degree to which the elements inside a module belong together [Wikipedia]
So, what does “sticking together tightly” and “belong together” mean in software?
Let’s take a look at the following image:
We can see that every arrow in the image points in some direction. From the perspective of the arrow direction, this system is not highly cohesive.
Now let’s notice that some arrows point in the same direction:
Let’s take the arrows that point in the same direction and group them into subsystems:
Now all the arrows that point in the same direction i.e. represent the same vector are grouped together and the cohesion in each subsystem is high.
Ok, now let’s try to apply this to software. We can map the concepts above to the software development in the following way:
- Every subsystem on the image represents a software module.
- Every arrow direction represents a different reason to change.
So, in order to achieve high cohesion in your code, you should group together the parts of code that have the same vector of change.
Let’s see an example. Say you have an online store that allows users to order some products online. For each order, an invoice must be created. The following is a simplified representation of one possible structure:
Is the solution above cohesive? Do the elements of the Ordering module have the same vector of change?
The purpose of the Ordering module is to allow a user to place an order for some products they want. Imagine the following two scenarios:
Scenario 1 – Accounting law changes: Imagine some part of the accounting law related to invoicing changes and some additional information needs to be added to every invoice. Your application needs to be modified in order to support the new invoices. You will have to go to the Ordering module and change the parts of code that are related to invoicing. So, nothing changed in your business model and ordering works the same way as before, but you need to modify the Ordering module anyway.
Scenario 2 – Ordering process changes: Let’s say you decided to change your business model and add some additional step to ordering process (e.g. golden membership discount for regular customers) which your application doesn’t support at the moment. You need to go to the Ordering module and change the parts of code that are related to ordering.
As we can see, Ordering module with the current structure has two reasons for change. It is affected by changes in invoicing process and by changes in ordering process. This indicates that our Ordering module is not cohesive. We can fix this by applying the same principle as with directed arrows from the beginning of the post:
- Identify parts of the module that have the same vector of change
- Move them to separate modules
We can see that Scenario 1 can affect
OrderItem and Scenario 2 can affect
Invoice. So, we can move those classes to separate modules, which will result in the following structure:
Now we have two modules that consist of elements that have the same vector of change and each of them is highly cohesive.
We can notice that those two modules are connected and we should make that connection as loose as possible, but this is a separate topic.