SOLID Design Principles - Single Responsibility Principle
In Object Oriented Programming paradigm, SOLID refers to a set of (class) design methodologies that are used to "structure" your (OOP) code more efficiently to make it more understandable, flexible and maintainable.
No article about SOLID principles can be written without giving the due credit to Uncle Bob or Robert C. Martin, who has been advocating and promoting these principles since late 90s.
SOLID is an acronym for
- S - Single Responsibility Principle
- O - Open/Closed Principle
- L - Liskov Substitution Principle
- I - Interface Segregation Principle
- D - Dependency Inversion Principle
In this first part, I will share my knowledge about the first principle Single Responsibility, also referred to as "SRP", and see what IT IS and what IT IS NOT.
SRP is one principle which is really easy to explain but definitely confusing/difficult to implement. Lets see why. As per Uncle Bob, Single Responsibility Principle states that
"A class should have One and ONLY One responsibility"
Really Easy, Eh?
However, a lot of developers get confused by this definition of SINGLE Responsibility. So, Lets first try to summarize what SRP IS NOT.
1. Some developers have the opinion that each Public method of a class represents ONE Responsibility. However, if we agree to that, implementing SRP would mean that each class in our application should only have a single method, which is not a good way to structure classes.
2. SRP does not have to do anything with the size of your class in terms of lines of code. (Although, it will definitely reduce the size of your classes, substantially, when implemented in a right way.)
What IT IS
Well, because of some degree of ambiguity in its definition, different people interpret the SRP in their own ways. To make it unambiguous, Robert C. Martin, later defined it as
"A class should have only one reason to change."
Makes Sense? Nah. Still Ambiguous.
Understanding Cohesion
It is very important to understand about Cohesion to better understand about SRP. Cohesion can be described as the relationship of all the Data and Methods of a class and the measure of the reason to put them together.
To simplify, it helps us to understand - to what extent a method (or for that matter Data) is related to the rest of the code in the class and what purpose it serves to put that method in that class.
Lets look at some code. YAY... Consider the following example. (I have omitted the detailed code for brevity)
Class Person
{
string fName,
string lName,
string mobile,
.
.
//constructor
public void Person(necessary arguments go here)
{
//Initialize Data members
}
public Person GetPersonDetails(decimal Id)
{
//Create DbConnection
//SQL SELECT where PersonID = Id;
//Fill values in Person object;
//return Person;
}
public decimal SavePerson(Person objPerson)
{
//Create DBConnection
//Write INSERT Query to save details passed in objPerson.
//return ID on success
//show Message to User
}
public ArrayList<Person> GetPersons(string condition)
{
//Create DbConnection
//SQL SELECT where Condition;
//Fill values in Person objects using foreach;
//return Arraylist<Person>;
}
public boolean ResetPassword(string password)
{
//Create DBConnection
//Write UPDATE Query to update the new password
//Create SMTP object and send Email
//return true on success
}
}
Many developers tend to write Such Business classes, however, this breaks the SRP at multiple occasions. Although, it seems to have a cohesive code that deals with Person object only, there are multiple reasons of change in this code. Lets analyse in detail:
1. The only responsibility or "Reason of change" for the Person class should be if we ever want to add/change a functionality of the PERSON, which may be addition of another field say "Salary" or "Department"
2. This class depends upon multiple other classes/libraries that can be a reason for change in future.
a.) If all such business Classes handle the DBConnection (or any Database dependent code) in the business objects, a decision to change the Database will need the change in the class.
b.) Person class uses some SMTP email server to send the Emails. If we ever think of changing or upgrading the Email Server, the Person class have to change.
c.) Person class also manipulates UI of the application by showing messages to the User. If we ever decide to change the format of the message or more commonly, go with a multilingual UI, the Person class has to change.
So, we should try to collate and envision all such reasons that may cause a change in our future design, and try to write separate classes dealing with those responsibilities. For example,
1. Our application should have a DB Class that deals with Database jargon. The reason for change of DB class will be if we ever decide to scale or change to a different Database. The rest of the classes in the application need not know about this change as long as the input and output of that class remains the same.
2. Our application should have a single Email class that encloses the logic to connect to a server and deals with Email operations.
3. Same goes for a class for Showing Messages or Logging Errors and so on.
- Do Note that all the public functions related to the Person class will still remain in Person class (Cohesion), however, we structure our code/classes in a way to create separate classes to handle responsibilities that do not Belong to the Person class.
Benefits
The main benefit of following SRP is to reduce the effect of bugs/changes and improve the testing efficiency of our code. As said above, if a single class contains code that may change for multiple reasons, we would need to test that class and all its dependent classes, whenever the code changes because of any of those reasons.
In our Example above, all the classes using Person class will have to be tested, if any of the following happens.
1. Change in Database Connections/Servers OR
2. Change in Email Server or its configurations
3. Change in Format of UI messages or language and so on.
4. And ofcourse, the change in the Person Object itself.
Analyzing such test scenarios also helps us in understanding the responsibilities OR reasons of change for a single class.
So, Single Responsibility Principle has to deal with how you structure your classes cohesively so that the code in that class should only be present there if it has a relation to the purpose of that class. Your code may choose to use other classes (like DB or Email) using a contract or interface but not know about any detail of that code and changing that code should not impact YOUR Class or any other classes using your class.
I hope I have been able to make some sense. Do let me know your thoughts/questions and I will try to answer in the comments.
Senior Frontend Developer at Pink Triangle Press
5 年Looking forward to explanation of other SOLID principles as well... And I love your examples! Thank you
Software Engineer| API Development| Backend Development | JavaScript | Java | nodejs | python | Web Development | Spring Boot | Django | AngularJs
5 年Explained SRP in an easily understandable manner.?
Mobile Apps || Android || React Native || Kotlin || SOLID Principles
6 年Nice article
Tech Lead - Ruby on Rails (ROR)
6 年Thank you sir for your detailed description about SRP.
Co-Founder and Director at Zapbuild Technologies
6 年Really Crisp and Detailed explanation of SRP. A lot of articles miss the core point about cohesion and coupling of classes and generally focus on repeating the definition given by R. Martin. Very well written. Looking forward to the next articles in the series