Isn't Class Violating Single Responsibility Principle By Definition?
I had a hard time understanding Single Responsibility Principle (SRP). I first saw its name in SOLID principle. At first glance, the idea was straightforward: "Every class should only have one responsibility." But with a second thought, it doesn't make sense! In Object-Oriented Programming, a Class is responsible for both storing the data and providing the behavior. Isn't Class itself violating SRP by definition?
Yes, we should all write functional code!
If we take SRP to the extreme, then we would only write two types of classes:
- Value objects, which only hold some data.
- Service objects, which only serve some functions.
In this case, our code would be functional, but with some object-oriented boilerplate.
- Value objects are data structures wrapped in classes.
- Service objects are functions wrapped in classes.
But this conclusion is based on the assumption that the R in SRP means programming-level responsibility: data or function. What if we understand responsibility in a different way?
No, a class should only have one business-level responsibility!
I learned another interpretation of SRP from Robert Martin's Clean Code:
A class or module should have one, and only one, reason to change.
This interpretation is better: for the same "reason to change", we may need to change data and behavior at the same time, so classes make sense again. But understanding "reason to change" was still hard to me. Is extracting a helper class a reason to change? Is handling a new edge case a reason to change? Is adding a new feature a reason to change?
The Aha moment came when I read this blog post from Robert Martin:
The reasons for change are people. It is people who request changes.
Then I realized my confusion came from different levels of "responsibilities".
Data/Functions are programming-level responsibilities. But the R in SRP means business-level responsibility. The reasons to change at business-level come from business person: stakeholders, clients, or users.
Take the classic MVC model for example, the different reasons for them to change are:
- Model
- "We need to store more data."
- View
- "We need to change how we display this data."
- Controller
- "We need to use a different workflow."
As you may see by now, SRP is a vague principle. It's hard to understand because different people hold different definitions for "responsibility". A SRP violation at one level may meet SRP in another level. It's highly context-dependent.
Principles are only guidelines
I don't mean to say SRP is a Hoax. SRP is a highly abstract summary. Learning it has taught me so much about how to write good software.
That being said, principles are only guidelines. My rule of thumb is to make it work first, then refactor to make it right. Use our best judgments at every step. And use these principles as guides when refactoring the code.