- Home>
- Design Patterns>
- The Single Responsibility Principle
Recently, I read the book “Clean Architecture” by Robert C. Martin. Overall, this is a great book with a wealth of information on software design principles to guide developers to build scalable, maintainable and flexible applications. A core part of the book discusses about six design principles which together make up the acronym SOLID.
The SOLID acronym represents the six principles:
In this post, I give a recap of the Single Responsibility Principle, which is the first one in SOLID.
I have heard of the Single Responsibility Principle before reading the book. However, the way I understood the principle was that a class or function should just do one thing. This understanding is not accurate. In fact, the author explains that a module should only change when a user or a group of user requires that change, which the author generalizes and refers to as an actor. Examples of an actor could be a CFO, CTO, Finance department, DBA etc …
The book gives an example of a class which violates the SRP. The Employee class is for managing employees and have methods like calculatePay()
, reportHours()
and save()
. The Finance department has a say in how the calculatePay()
works. However, it does not need to care about the reportHours() which the Human Resources department relies on for its reports. Both departments do not need to concern with how the save() method works to persist the data, as that is for the DBA .
Clearly, the Employee class violates the single responsibility pattern because it is responsible for multiple actors: The Human Resources department, the Finance department and DBA . Now, whenever one of the departments requests a change which result in changes to the Employee class, those changes can potentially impact the other departments even those they don’t want or need the changes. The author gives an example scenario.Initially, both the Finance and Human Resources department have the same rules to determine the number of regular hours out of the total hours the employee has worked. In the codes, the calculation of regular hours reside in a common method, regularHours() which both the calculatePay() and the reportHours() call. After sometimes, the Finance department changes the number of hours it considers as regular hours for the purpose of paying an employee. Upon updating the regularHours() method to implement the change and releasing to production, the app no longer produces correct reports for the Human Resources department because the rules are no longer correct for them.
Per the Single Responsibility Principle, we should extract the three methods into separate classes. The diagram below shows an example of a way to accomplish this.
The Employee classes just delegate to the different classes to do the calculation. Furthermore, we can implement the different implementations of regularHours() for the different departments and relate them together via interfaces.
In summary, the Single Responsibility Principle encourages us to separate codes that change for different reasons so that when we make change to an existing module, we avoid breaking other modules that do not have to do with the change.
Clean Architecture: A Craftsman’s Guide to Software Structure and Design (Robert C. Martin Series)
Common frameworks, libraries and design patterns I use
Notes on component coupling
Notes on Component Cohesion
Notes on the three programming paradigms
Notes on The Clean Architecture
Notes on The Dependency Inversion Principle
Notes on the Interface Segregation Pattern
Notes on Barbara Liskov paper on data abstraction and hierarchy