The Single Responsibility Principle (SRP) of SOLID

The Single Responsibility Principle (SRP) of SOLID

Understand SRP and how can you make your code better.

Introduction

In this article, I will address the first principle of SOLID, known as the Single Responsibility Principle (SRP).

First, what is SOLID?

SOLID is an acronym representing five fundamental principles of object-oriented software design and architecture, identified by Robert C. Martin (Uncle Bob) around the 2000s. The acronym SOLID was introduced by Michael Feathers, after observing that the five principles could fit into this word.

Following these principles can result in a system that is more comprehensible, flexible, and modular, which is easy to scale, modify, and test.

Definition

The Single Responsibility Principle (SRP), the first of the five principles of SOLID, is a fundamental concept in object-oriented software development.

This principle states that a class should have only one reason to change, meaning it should be responsible for only one part of the software's functionality.

You should apply this principle not only to classes but also to functions, modules, etc.

An analogy for better understanding

Imagine a team in a restaurant. In this team, we have various functions: cooks, waiters, and the manager. Each of these team members has a unique responsibility. The cooks prepare the food, the waiters serve the food to the customers, and the manager takes care of the restaurant's administration. Imagine the chaos if a single person tried to perform all these tasks, it would generate a totally inefficient and confusing system.

Similarly, a class in software should specialize in a single functionality or responsibility. This makes maintenance easier, code comprehension better, and aids in reusability.

SRP in software development

Let's observe an example that violates the SRP. The class below deals with user details and at the same time manages the storage logic of those details.

class UserManager:
    def __init__(self, user_name, email):
        self.user_name = user_name
        self.email = email

    def change_user_email(self, new_email):
        # Logic to change the user's email

    def save_user(self):
        # Logic to save the user in the database

In this code, UserManager is responsible for both managing user details and the storage logic (data persistence). This violates the SRP, as we have more than one reason to modify the class.

To correct the SRP violation, we can divide the class into two: one to manage user details and another to handle data persistence.

class User:
    def __init__(self, user_name, email):
        self.user_name = user_name
        self.email = email

    def change_email(self, new_email):
        # Logic to change the user's email

class UserDataStorage:
    def save_user(self, user):
        # Logic to save the user in the database

Shall we see another example?

Below, we have a class that generates reports on products and also saves them in a file. This class does too much by dealing with both formatting and data persistence.

class ProductReport:
    def __init__(self, products):
        self.products = products

    def generate_report(self):
        # Logic to generate report

    def save_report(self):
        # Logic to save report

To adhere to the SRP, we can create a separate class for generating the report and another for saving the report to a file.

class ProductReportGenerator:
    def __init__(self, products):
        self.products = products

    def generate_report(self):
        # Logic to generate report

class ReportSaver:
    def save_report(self, report):
        # Logic to save report

Tips for applying the SRP to your project

  1. Identify responsibilities: Analyze your classes to identify different responsibilities. Each responsibility is a potential axis of change.

  2. Divide and conquer: If a class has more than one responsibility, consider dividing it into smaller classes, each with its own responsibility.

  3. Code reuse: Classes with a single responsibility are easier to reuse because you can use them in different contexts without bringing unnecessary functionalities.

  4. Testability: Classes focused on a single responsibility are easier to test because you do not have to deal with multiple functionalities during the testing of a specific functionality.

Conclusion

The Single Responsibility Principle is essential for sustainable and high-quality software development. Classes, functions, modules focused on a single responsibility ensure efficiency, maintainability, and clarity of code. By applying the SRP, you create a solid foundation for a robust software architecture, facilitating the evolution and maintenance of your project.

Thank you so much for reading this far. Find me on other social networks.