DEV Community

Mateusz Gajda
Mateusz Gajda

Posted on

Do you know GRASP? Part 3 - Cohesion and Coupling

Cohesion and Coupling are very popular terms in Software Engineering. Also, GRASP tells something about it. Let's take a look at what these patterns tell us about these weirds words.

Coupling

What everybody knows about coupling is that good practice is to keep coupling low. It is because coupling means how one element relates to another. As coupling grows, the dependence of different modules on each other increases. So we can say that if the coupling is low, changing something in one class shouldn't affect another.
We can also notice another benefit of low coupling. If classes are independent or have a low number of dependencies, they are easy to reuse. They are also easy to test because we have fewer dependencies to manage :)

High coupling makes it very difficult to maintain or introduce any features into our codebase. From the client perspective, it is also very irritating, because the client needs to wait much more time for new features. So he need also to pay more for our work.

As we divided coupling for low and high, let's consider how to distinguish them? High coupling is when one class use or depends on the implementation details of another class. For example, we use some properties from another class directly. So we depend on implementation detail. In case when this property will be changed, we will be forced to change first class. Low coupling is when we depend on abstraction and encapsulation. It's when the second class exposes some public methods, which allows us to access important data. It's because when implementation details have been changed, our public contract will be the same. So we don't care what is going on inside the method, we just use it.

There are different types of couplings, below is a list ordered from least accepted to the most accepted:

  • Content Coupling - when one module talks directly with another module. It means that module X use implementation details from module Y.
  • Common Coupling - when two separated module depends on some shared state. It could be some variable for example. In this case, they don't talk directly to each other, but by some other value.
  • External Coupling - if two modules want to talk to each other, they use some external interface. When the interface has been changed, it can no longer communicate anymore.
  • Control Coupling - one module tells another module how to do his job. It can be done by passing a flag, which will manipulate another module by turning off/on some kind of business logic.
  • Stamp Coupling - we pass some data structure from one module to another, and this module use only part of the passed data to do their job. We depend on the whole data structure even if we need only some data from it.
  • Data Coupling - we pass from one module to another only data which are necessary by this module to do their job.

So for us, as a developer, important is to keep coupling low. Maybe not as low as possible, because sometimes it is useless, and increase the level of complexity, so we should be pragmatic.

Cohesion

When we talk about cohesion, we mean how focused the class is on their task. If the class has high cohesion we see that in the class are only methods related to the intention of the class. Thanks to that, when we have high cohesion, the modularity of our system is increasing. So if we keep things related to each other in one class or module, the bindings between other classes will be smaller. What will cause the changes will concern some small areas and not half of the system. If the class has low cohesion, we can notice inside the class some methods not related to it.

Like the coupling, cohesion has also some types. Below is a list ordered from least acceptable to the most:

  • Coincidental - two functions are in one module by accident and nothing connects them. Classes like utilities or shared are the best example of the coincidental cohesion.
  • Logical - when, at first glance, the two entities are connected, but after deeper consideration, they would turn out to be completely different. For example, two entities with similar names, but differentiated responsibility.
  • Temporal - two functions are in the same module because they must be executed at the same time.
  • Procedural - the procedure needs some operation to be executed. So we group all operations into one module
  • Communicational - there are functions in the module that use the same data
  • Sequential - there is a function, which returns data which the next function needs. So we create a pipeline of executions.
  • Functional - functions are in one module because together they create a whole feature.

Let's take a look at an example:

class Employee{
  id: string;
  name: string;
  address: Address;
  salaries: Salary[];

  getName(){}
  getAddress(){}
  getSalaryReport(){}
}

Here we have a class Employee with two methods, get name, and get a salary report. We can say that this is natural that employee has a salary, but are we really need this information in employee class? Should employee be responsible for creating a report? In my opinion not. What we should do? We should create a separated class focused on this functionality, like below:

class Employee{
  id: string;
  name: string;
  address: Address;

  getName(){}
  getAddress(){}
}

class EmployeeSalary{
  employeeId: string;
  salaries: Salary[]

  getSalaryReport(){}
}

Now, we have an independent class. When we want to generate the report for an employee we retrieve EmployeeSalary class from the database and execute method getSalaryReport(). Thanks to that Employee class don't know anything about the salary, because it is not important information for Employee.

Conclusion

In conclusion, cohesion means how related and focused the responsibilities of an software element are. Coupling refers to how strongly a software element is connected to other elements.
As we can see, taking care about low coupling and high cohesion helps us creating class with one specialization, without any additional dependency. It will help us in the future, when we will be forced to change an implementation. When we spend enought time thinking about, how to design our system and apply this patterns, we save time in the future. We will also make our client happy, what is very important, because we create software for the business.

In the next part, I write about last 3 patterns: Polymorphism, Protected variations and Pure fabrications.

Top comments (1)

Collapse
 
anduser96 profile image
Andrei Gatej

Great series! Thank you 👍🏼