Skip to content

Single Responsibility Principle

Subrata Sahoo edited this page Jul 19, 2024 · 5 revisions

A class should have one and only one reason to change, meaning that a class should have only one job.

What does it mean?

A class should be responsible for only one actor or entity. If a class is catering to multiple actors/entities, it could be breaking the single responsibility principle.

Advantages

  • Enhanced readability: Small & clean classes.
  • Improved maintainability: Changes are isolated to specific aspect of the application.
  • Simplified testing: Classes can be tested in isolation making unit testing more straight forward & reliable.
  • Reduced risk of errors: By isolating responsibilities, changes to one part of the system will not induces errors in unrelated areas.
  • Better reusability: Classes more focused on a single responsibility are more likely to be reusable in other parts of the application.

Pitfalls

Problem Description Solution
Over-Fragmentation Applying SRP too rigidly can lead to an excessive number of small classes, each handling a single responsibility. This can make the system fragmented and harder to navigate, as it might require interacting with many small components. Balance is key. Meaningful responsibilities and avoiding creation of too many classes for minor responsibilities. Group related responsibilities where appropriate.
Increased Complexity Breaking down responsibilities can sometimes lead to increased complexity in the codebase. The interactions between numerous small classes can become complicated. Ensure that the design remains understandable. Use descriptive class names and maintain clear boundaries between responsibilities to keep complexity
Class Explosion Following SRP can lead to a proliferation of classes, which might make the codebase harder to manage and understand. Regularly review of design to ensure that classes are not being overly fragmented. Using composition and well-defined interfaces to keep the number of classes reasonable.
Difficulty in Identifying Responsibilities Determining what constitutes a single responsibility can be subjective and challenging. Misidentifying responsibilities can lead to classes that are either too broad or too narrow. Thoughtful design and refactoring. Involve multiple perspectives, including peer reviews, to ensure that responsibilities are correctly identified and assigned.
Refactoring Overhead Applying SRP might require significant refactoring of existing code, which can be time-consuming and introduce new risks. Apply SRP incrementally. Refactor the codebase gradually, focusing on one area at a time to manage risks and reduce overhead.
Potential for Over-Engineering Striving to adhere to SRP in every aspect can sometimes lead to over-engineering. This might involve creating overly complex abstractions for very simple tasks. Apply SRP pragmatically. Ensure that abstractions and class separations genuinely improve maintainability and not just complicate the design.
Increased Indirection Breaking down responsibilities might introduce additional layers of indirection which can sometimes lead to performance concerns or make debugging more difficult. Ensure that the added indirection does not adversely impact performance or clarity. Profile and optimize when necessary.
Misalignment with Other Principles Striving for SRP might sometimes conflict with other design principles like the Open/Closed Principle (OCP) or the Interface Segregation Principle (ISP). Consider all SOLID principles together when designing systems. Ensure that the application of SRP aligns with the overall design goals and principles.

Example Explained

Book class in WithOutSRP folder violates the single responsibility principle by handling multiple responsibilities holding book data, saving book data to database, printing & emailing.

In the refactored example in the WithSRP folder:

  • The Book class is only responsible for holding book data.
  • The BookRepository class is responsible for saving book data to a database.
  • The PrintingService class is responsible for printing.
  • The EmailService class is responsible for sending email notifications.

By separating these responsibilities, each class now has a single reason to change, making the system more modular, maintainable, and easier to understand.

Clone this wiki locally