Low Coupling, High Cohesion is a programming principle that says that your classes should be coupled with other classes as little as possible but the cohesion inside your classes should be as high as possible.
I like this concept and always keep it mind when developing.
It helps to keep my code clean and promotes all the other clean code principles.
It also applies to modules but I will focus on classes since that is where you will apply it, most of the time.
What does it mean?
Low coupling means your class should be coupled as little as possible with the other classes in your project.
A class is coupled with another class when it uses its methods and properties.
The more a class uses the other class the more coupled it is to it.
We can also say that the class knows the other class.
A class should know the other classes as little as possible.
When classes in your project use other classes a lot and know all of their internals, like what properties they have, what properties those properties have, your class has High coupling.
This leads to a sort of entanglement called spaghetti code.
Spaghetti code is an expression used for this kind of hard to modiffy, highly coupled, bad code.
Why is it called spaghetti code?
Because classes are called through the entire project, just like spaghetti noodles go through the entire bowl.
Trying to modify or extract a single object is frustratingly hard.
This kind of code suffers a lot of fragility.
We talked about fragility in the symptoms of bad code episode.
Fragility exists when a small change in one place breaks the project in other places, some that should have nothing to do with your current scope.
When writing clean code you are trying to make the code easy to read, easy to maintain and with little or no bugs.
If you keep the coupling low, when you change a class, your changes are local, and affect only a few lines of code.
On the other hand, in high coupled systems a change affects a lot of classes from your project.
The more places your change affects, the more likely it is to introduce bugs in those places.
Imagine telling your IDE to change the type of a property, and your IDE shows you two hundred classes that will be affected by the change.
That’s not a pleasant and comfortable moment.
In a low coupled environment you will only see one or two places affected.
Spaghetti code also leads to rigidity.
Rigidity happens when the code fights your changes, and even small changes take a lot of time to implement.
If your class is used in the entire project, so it has high coupling with almost all the other classes, it will be hard to change so your system will be rigid.
How to avoid high coupling?
You can do this by being careful of what goes into classes and what comes out of them.
So you have to be careful what parameters you send and what you return.
You should only get and return what you need, not more.
In the case of parameters, let’s assume your code needs the title of a book, in order to display it.
Don’t send the entire book object.
Send only what it’s needs: the title string.
If you send the entire book object, you couple the PagePrinter class to the Book class.
Why does the printTitle method and the PagePrinter class need to know how a book works and the fact that it has a title?
What if tomorrow you decide books don’t have titles.
Why should your PagePrinter class care about this?
Your printer class should know it’s surroundings as little as possible.
If you can separate PagePrinter from Book you should do it.
The fewer objects PagePrinter knows about, the lower it’s coupling is to your system.
The lower it’s coupling the better.
The lower the coupling the easier it is to maintain it.
The lower the coupling the more reusable it is.
Sending the entire book object makes it less reusable.
Imagine you will work with Movies next.
Having a simple title string as a parameter will help you.
All the code for printing titles will be already written, and you won’t have to refactor, or write a new printTitle method for Movie.
You can also promote low coupling using encapsulation.
Instead of having your system open and passing objects all over the place you can encapsulate your state and behaviour and return relevant information.
For instance let’s say your book has a report class that contains a short description.
You want to print your book’s shortDescription.
An easy way would be to use the book object to get the report object and get the short description from it.
But why do we know so much about the book here, outside of the book class.
Why do we know the fact that a book has a report.
It’s intuitive to know a book has a description.
But the fact that it has a report property seems more like something that only the book should know.
This is something that the book class should encapsulate.
So maybe we should have a getDescription method in the book class, and let the book object handle it’s own internals and state.
It’s good to always have in mind the fact that you should minimize coupling.
It’s best if objects know a lot about themselves and little about the outside world.
How do objects get to know themselves?
Well, through encapsulation and low coupling high cohesion.
Using encapsulation they hide their state and acquire behavior, thus getting to know themselves.
Through low coupling and high cohesion they get to know only themselves, and know themselves well.
Cohesion refers to the degree to which the elements inside a class, belong together.
The more specialized your objects are the more cohesion they have.
If your objects respect single responsible principle and only do one thing they will have high cohesion.
For instance let’s say your class calculates some statistics.
In order to do that it reads a few numbers from a file.
You realize this lowers your class cohesion.
This is because the calculating statistics logic is cohesive with itself.
The working with files logic is also cohesive with itself.
But the statistics logic and the reading files logic are less cohesive together.
So you decide to extract the files reading logic into another class and use that class with composition.
Now, instead of one class with low cohesion you have two classes, each with high cohesion.
But didn’t this increase coupling, since the two classes are coupled by composition?
Well, that would be the wrong way of looking at it.
They should be coupled to a certain degree, because they need each other.
A certain degree of coupling between them is natural.
But you could say you decoupled your statistics class from the file reading libraries.
Also you decoupled your file reading code from the statistics libraries.
So overall coupling decreased and cohesion increased.
Coupling and cohesion are two related notions.
Usually the more one increases the more the other decreases.
Whenever you refactor and end up deleting imports and dependencies you should feel good.
Most likely you are lowering coupling and increasing cohesion.
Like a lot of clean code concepts, this one is also related to small functions.
If you have small functions and classes, most likely you won’t do things that require a lot of coupling.
Also small functions and classes attract high cohesion, since you are not doing a lot of things in a small class.
This article is part of the “Low Coupling, High Cohesion” episode from my Clean Code course. You can watch the Clean Code courses here:
– Watch Clean code with Java examples course on Udemy
– Watch Clean code with PHP examples course on Udemy
– Watch this Clean code with Java examples – Basics for free here AND get 2 FREE months of skillshare.com Premium