Understanding the Single Responsibility Principle
Imagine, your Project Manager(PM) just assigned you an ‘X’ feature to be implemented. You are about to implement it, and you realize that you need to change a few files. And without further ado, you start working on it. After a bit of here and there, you are ready to create a Pull Request to be merged. You can see the changes you have made — and to your astonishment, those couple of files turned out to be 20–30 odd files.
Now my question to all — How is that possible for such a simple feature?
Let’s check out a simple principle to avoid such a situation.
What is the Single Responsibility Principle?
- A class should have only one “Responsibility”.
But First, What is Responsibility?
It means that it should have only one reason to change. Also, it can be a module, entity, or a function.
Before you start coding, you should always keep in the mind if — the class/function/entity has multiple responsibilities(or multiple reasons to change). If you agree then it’s always better to separate the two. For example, you are working on ‘Y’ feature and it has two functions — fetching and displaying of the data. Now, it is better to separate both the components. If you see a shift in the logic of retrieving the data then only the first component will change. Further, if for any reasons the UX designer changes the UI component(table to list); the class that is responsible for rendering the data will only change. Hence, both the responsibilities works on its own.
“Gather together the things that change for the same reasons. Separate those things that change for different reasons.”- Robert C. Martin (Uncle Bob)
The image below summarises a component having multiple responsibilities.
Before jumping to the positive of SRP and its implementation. Let’s first have a look into the two important terms-
Coupling
- The degree to which a class, method or any other software entity, is directly linked to another.
When one class is linked with another with high coupling, we end up changing both the components when we want to change only one. It is also known as a degree of dependence.
What is Cohesion?
- Two or more parts of a system work together to obtain better results than each part individually.
It Refers to what the class (or module) can do. Low cohesion would mean that the class does a great variety of actions. High cohesion means that the class is focused on what it should be doing, i.e. only methods relating to the intention of the class.
Hence, through SRP we can achieve the following:-
- Low Coupling.
- High Cohesion.
- Code easier to understand and maintain.
The SRP is about restricting the impact of change
Example
Here is a very basic example covering how to implement the SRP:
// Without SRP
class Address {
public string City {
get;
set;
}
public string State {
get;
set;
}
public void Save() {
//Save to database code.
//Open db connection.
//Make some logic checks.
//DB CRUD operations.
//Close connection.
}
}
Here, it violates the SRP because of the following reasons:-
- It can change because we want to add a specific attribute for an address- it’s postal code, for example.
- It can change because our database structure changes and we need to update the data operations, or because we want to save our address in a different format.
- Another problem with this code is that the size of the file will continue to increase because it has two reasons to change. Hence, it will be difficult to maintain.
So, How do we make it simpler?
We move the logic of saving the data into another class
// With SRP
class Address {
public string Author {
get;
set;
}
public string Title {
get;
set;
}
}class PersistAddress {
public void Save(Address addressToSave) {
//Save to database code.
//Open db connection.
//DB CRUD operations.
//Close connection.
}
}
The benefits of the above code are:
- The class Address does not need to take care of the changes that occur in the class connected to the database.
- The code is easy to maintain and understand.
- Coupling is low and Cohesion is high.
You can find another great example in this article published by Robert C. Martin(Uncle Bob).
Conclusion
Refactoring a code is inevitable. But as coders, it’s our responsibility to restrict its depth and ensure it does not suck up too much of development time. Hence, using SRP can ensure that we do not need much refactoring.
We want to increase the cohesion between the things that change for the same reasons, and we want to decrease the coupling between those things that change for different reasons. So, whenever you start coding stop for a minute and differentiate — The components having different responsibilities and the components having the same responsibilities(or reason for change).