Grokking SOLID Design Principles
Vote

0% completed

Coupling and its Relation to the Single Responsibility Principle (SRP)

What is Coupling?

General Example: Tightly Connected Devices vs. Independent Devices

Where We Start: One Class Doing Two Jobs

Step 1: Move the Database Work Into Its Own Class

Step 2: Depend on an Interface Instead of a Class

Coupling and SRP

What is Coupling?

Coupling is how much one class depends on another class.

Notice that coupling is a relationship between two things. A single class on its own is neither tightly nor loosely coupled. It has nothing to be coupled to. Keep that in mind for the example below. The first version of the code has one class only, so its problem is not yet a coupling problem.

We aim for low coupling, which means a class can be changed, replaced, or tested without forcing changes to other classes. High coupling means the opposite: a change to one class forces a change to the other.

General Example: Tightly Connected Devices vs. Independent Devices

Imagine a TV and a remote that only work together. The remote controls this one TV, and the TV accepts no other remote. This is high coupling. You cannot replace one without replacing the other.

A remote that controls one specific television is high coupling: replace either and you replace both. A remote and devices that agree on a shared standard is low coupling, which is what an interface does in code.
A remote that controls one specific television is high coupling: replace either and you replace both. A remote and devices that agree on a shared standard is low coupling, which is what an interface does in code.

Now, imagine a universal remote that works with many devices, and a TV that accepts any remote. This is low coupling. Each device can be swapped on its own.

Where We Start: One Class Doing Two Jobs

Here is a Student class that holds student data and also knows how to write that data to a database.

Python3
Python3

. . . .

This class has two jobs. It represents a student, and it talks to a database. That is the cohesion problem from the previous lesson, not a coupling problem. There is only one class here, so there is nothing for it to be coupled to yet.

Splitting the two jobs apart is still the right first move.

Step 1: Move the Database Work Into Its Own Class

We give the database work its own class and let Student call it.

Python3
Python3

. . . .

Each class now has one job, so cohesion is better. But look at what we created. There are two classes now, so we can finally talk about coupling, and the coupling we have is tight.

Student names MySqlDatabase directly. That has three costs:

  • You cannot store students anywhere else without editing Student.
  • You cannot test Student without a real MySQL server running.
  • A change to how MySqlDatabase is constructed forces a change in Student.

Extracting a class moved the database work out of Student. It did not make Student independent of it.

Step 2: Depend on an Interface Instead of a Class

We describe what Student needs as an interface, and let Student accept any class that satisfies it. The caller decides which one to hand over.

Python3
Python3

. . . .

Now Student names no database at all. It names StudentRepository, which is a short list of methods rather than a working class. Swapping MySQL for Postgres means writing a new repository class and passing it in. Student does not change.

Testing gets easier for the same reason. The in-memory repository above is all a unit test needs.

This move has a name, and it is the last of the five principles: depend on abstractions, not on concrete classes. Coupling is the problem that principle solves.

The three steps side by side. Step two extracts a class and looks like progress, but Student still names one specific database. Only step three, where Student names an interface the caller supplies, actually lowers coupling.
The three steps side by side. Step two extracts a class and looks like progress, but Student still names one specific database. Only step three, where Student names an interface the caller supplies, actually lowers coupling.

Coupling and SRP

The two ideas are related but they are not the same, and this example shows the difference clearly:

  • Splitting responsibilities is what SRP asks for. It fixed cohesion. On its own it left Student tightly coupled to MySqlDatabase.
  • Pointing the dependency at an abstraction is what fixed coupling. SRP does not ask for this by itself.

So SRP tends to lower coupling, because a class with one job needs fewer collaborators. It does not guarantee it. After you split a class, check what the two new classes depend on. Extracting a class can leave you with two tightly coupled classes where you had one messy class.

Rohit Bhanot

Rohit Bhanot

· 14 days ago

As others commented, while conceptually its trying to decouple two classes but because Student class hardcoded the database backend it created a high coupling. I think the right model would be to provide the database backend as input to Student class and use that backend to get a db_manager instance and then just call self.db_manager.save()

Show 1 reply
V

vkvikaskmr

· a month ago

Sounds confusing to me. In the first example one class is doing everything so there is no other class to depend on. In the second example Student depends on DatabaseManager class (not an interface) and hence there is tight coupling between them

Show 1 reply
N

necas.radek

· 2 years ago

Hi, I like this course and how are different principles linked together in this part. I wanted to discuss the part where implementing SRP leads to low coupling. I think it can when it is doing well, but sometimes it might have an opposite effect. For example you have legacy code with class A with many responsibilities. You separate some responsibilities into new class B. But now class B can easily become tightly coupled with A because it was created (extracted) based on requirements of A. It can happen also when junior developers try to implement SRP blindly to their design. They have bigger functionality or use case. To implement it with SRP in mind they need to create classes with different responsibilities. But each class is then tightly coupled to the rest because it was created for th

Show 1 reply

Reading Progress

0%

On This Page

What is Coupling?

General Example: Tightly Connected Devices vs. Independent Devices

Where We Start: One Class Doing Two Jobs

Step 1: Move the Database Work Into Its Own Class

Step 2: Depend on an Interface Instead of a Class

Coupling and SRP