What exactly does “Low coupling, High cohesion” mean?

Eric Sabag
Wix Engineering
Published in
5 min readDec 2, 2021

As a developer, you’ve probably heard how important is to write modular, independent code. The SRP principle, as well as cohesion and coupling, may be mentioned.

But, when writing your code, did you ever consider these principles?
You might be a junior software engineer who believes these terms refer to difficult, complex design patterns that have nothing to do with you. You might even be an experienced frontend developer who has always connected these phrases with the backend guy.

In every codebase and for every developer, the “low coupling, high cohesion” notion is a basic, fundamental principle. It provides us with better-designed, easier-to-maintain code, allowing us to boost our productivity and develop new features more quickly. Furthermore, when you design your code correctly, testing becomes a lot easier.
So, what exactly does “Low Coupling, High Cohesion” mean?

Low Coupling

The degree to which separate modules rely on and are aware of one another is referred to as coupling.
Low coupling indicates that each module, class, or component should have as few dependencies as feasible and that modifying one module should have little to no influence on other modules.
Have you ever worked on a large project where a minor change in one module caused something completely unexpected to happen?
Low coupling is attempting to address this issue. By keeping code loosely coupled, which means the different modules don’t know the internal details of other modules, we can write code within one module without impacting other modules.
We also get the benefit of being able to easily reuse and rewrite modules.

High Cohesion

The way each aspect of a module is directly related to the module’s functionality is referred to as cohesion.
High cohesion means related codes should be close to each other. A single module’s elements should all functionally belong together and accomplish one particular goal.
Take the example of a large project as before. Have you ever had trouble understanding out what function is responsible for the details you possess in your module? Trying to debug it for an inordinate amount of time?
It’s difficult to figure out what code is related to your module if your code isn’t cohesive, and keeping track of all the many modules you need to bounce between will be challenging.
In a well-designed project, we can easily read, rewrite, and test our code since all of the related code for a module is found and functions together.

Low coupling, high cohesion example
An example of a low coupling, high cohesion system

To understand how these two terms should work together, remember that cohesion has to do with the elements within the module(or any other structure) while coupling talks about elements among different modules.

Let’s take a look at a less obvious example of frontend architecture to see how we can build clean, maintainable, and testable code that is simple to understand and maintain.

Booklist Application Example

We’ll build a basic booklist application, that displays available books and readers. For each reader, we’ll show the book he already read.

This is our end goal:

Booklist App
Our Booklist application

And for the(very messy) code:

Here you can see the app.js of our application, we’re using <Books /> and <Readers /> components.
Let’s take a look at the implementation of these components.

You’ve probably already found some flaws in the code.
First, there are some duplicated codes we can avoid, such as the code to style the card for each item, and the functions to get all the books are duplicated too.
Second, there is no obvious distinction between the UI and the logic. Our components are responsible for fetching the data, processing it, and styling it.
The Single Responsibility Principle is being entirely violated.

Thinking about these deeper, we should recognize some bigger problems that may arise if our project gets bigger in the future.
What if we want to add more books to a reader and add more attributes to the book object? Maybe we’ll want to remove a book and remove it from all the readers as well. The code may become too complicated and each change would require changing some other modules that may not be related to our task.
And, if we wish to test these new features, testing such code will almost certainly result in a huge mess and a waste of valuable developer effort!

Let’s try to refactor the code, making our lives much easier when maintaining it in the future.

To make things easier, we’ll keep App.js the same. It’s important to note that we could refactor the code even more, but we’ll keep it simple to make the important points clear.
Let's take a look at our new Readers.js and Books.js files and the new folder structure.

New folders structure
Folder structure

We can see that now we are using other modules to handle some of the needed tasks.
First, getting the resources of Readers and Bookings isn’t from an inner function of the component. Instead, we have an “api” folder that has a module for each resource. Now we don’t need to hold duplicate code, and adding more functionality like update or delete would be much easier.

Second, our component doesn’t handle the style for the card, and we have a specific component to handle the style. Here is the Card component:

After these changes, we can recognize our three kinds of modules: the API calls, the business logic, and the presentation layer.
Now we have a modular, component-based, layered code that helps increase our productivity and reduce risks when a change in one module is required.

This code above is only a small, simple example, but yet we have more readable, maintainable, and testable code than before the refactor. We can recognize that it led to an application that adheres to the SRP(Single Responsible Principle).

Next time you design your project, even if you are the front-end guy, ask yourself, “Can I improve this by making the code more loosely coupled? Can I improve this by making the code more cohesive?”

--

--