I am quite confused with the Single Responsibility Principle. The Principle states that there should only be one reason for the class to change.
The problem which I am facing is, any change to a method or any logic change in doing things would change the class. For example, consider the following class:
class Person{
public void eat(){ };
public void walk(){ };
public void breathe(){ };
public void run(){ };
public void driveCar(Car car){ };
}
Uncle Bob describes it as there should ONLY be a single person/Actor responsible for the change. I have the following two questions:
The Single Responsibility Principle applies to software components on all levels: methods, classes, modules, and distributed services. The Single Responsibility Principle itself doesn't include guidance about how large or small a responsibility for a component should be.
The Single Responsibility Principle (SRP) The idea behind the SRP is that every class, module, or function in a program should have one responsibility/purpose in a program. As a commonly used definition, "every class should have only one reason to change". The class above violates the single responsibility principle.
The Single Responsibility Principle (SRP) is the concept that any single object in object-oriented programing (OOP) should be made for one specific function. SRP is part of SOLID programming principles put forth by Robert Martin. Traditionally, code that is in keeping with SRP has a single function per class.
The argument for the single responsibility principle is relatively simple: it makes your software easier to implement and prevents unexpected side-effects of future changes.
- For the above class who is the actor/Person who can be responsible for the change?
An Actor is a user (including clients, stakeholders, developers, organizations) or an external system. We can argue if people are systems, yet that is not here nor there.
See also: Use case.
- Wouldn't any change in the logic of eating, breathing or walking change the class Person? So doesn't that mean that every method is a reason to change as its logic to doing things might change?
No, a method is not a reason to change. A method is something that can change... but why would it? What would trigger the developer to change it?
Part of the single responsibility principle is that code should interact at most with one external system. Remember that not all actors are external systems, however, some are. I think most people will find this part of the SRP easy to understand because interaction with an external system is something we can see in the code.
However, that is not enough. For example, if your code has to compute taxes, you can hardcode the tax rate in your code. That way, it is not interacting with any external system (it is just using a constant). However, one tax reform later, the government has been revealed as a reason to change your code.
Something you should be able to do is interchange external systems (perhaps with some additional coding effort). For example, changing from one database engine to another. However, we do not want one of these changes to translate into a total rewrite of the code. Changes should not propagate, and making a change should not break something else. To ensure that, we want all the code that deals with the database engine (in this example) to be isolated.
Things that change for the same reasons should be grouped together, things that change for different reasons should be separated. -- Robert C Martin
We can do something similar with the government example above. We probably do not want the software reading the minute of the congress, instead, we can have it reading a configuration file. Now the external system is the file system, and there would be code to interact with it, and that code should not interact with anything else.
Your code is defined by a set of requirements. Some are functional, others not. If any of those requirements change, your code has to change. A reason to change requirements is a reason to change your code.
Note: It is possible that you do not have all your requirement documented, however, an undocumented requirement is still a requirement.
Then, you need to know from where do those requirements come from. Who or what could change them? Those are your reasons for change. It could be a change in the politics of the company, it could be a feature we are adding, it could be a new law, it could be that we are migrating to a different database engine, or different operating system, translating to another language, adapting to another country, etc.
Some of those things are externals systems with which your code interacts (e.g. the database engine), some are not (the politics of the company).
You want to isolate them. So you will have code that interacts with the database, and nothing else. And you will have code that implements business rules, and nothing else. And so on.
Realize that even though the implementation of each part of your code will depend on something external, their interface does not have to. Thus, define interfaces and inject dependencies, so that you can change the implementation of each part without having to change the others… that is, the implementation of parts of your code should not be a reason to change the implementation of other parts of your code.
Note: No part of your code should have multiple responsibilities. Have parts of your code deal with each responsibility, and have part of your code with the responsibility of bringing other parts together. Similarly, if a part of your code has no responsibility… there is no reason to keep it. Thus, every part of your code should have exactly one responsibility.
For your code, ask yourself, what are the requirements of the Person
class. are they complete? From where do they come from? Why would they change?
For a more authoritative explanation of the single responsibility principle, see Robert C Martin - The Single Responsibility Principle (51 minutes, 8 seconds, English language) at the Norwegian Developers Conference, 2015.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With