Single Responsibility Principle (SRP)

Single Responsibility Principle (SRP)

SRP is part of SOLID design principles. With the help of SRP, we can maintain clean and robust source code.

SRP states that only one actor can change the module. In most of the scenarios, the actor corresponds business stakeholder.

The module can be a class, set of functions, package or source code.


Example: To illustrate, let's delve into a common scenario within an e-commerce company concerning order processing. In this context, the company is tasked with order processing for customers, warehouses, and accounting functions. The following pseudo-code outlines the process of order handling:

class OrderProcessor {
    public void processOrderForCustomer(...) { // Required for Customer Service
        // ...
        validateOrder(...);
        // ...
    }

    public void processOrderForWarehouse(...) { // Required for Warehouse Management
        // ...
        validateOrder(...);
        // ...
    }

    public void processOrderForAccounting(...) { // Required for Accounting
        // ...
        validateOrder(...);
        // ...
    }

    private boolean validateOrder(...) {
        // Validation logic common to all stakeholders
        // ...
        return isValid;
    }
}

In OrderProcessor class, we have a single class responsible for processing orders for three different business stakeholders: Customer Service, Warehouse Management, and Accounting. Each stakeholder's order processing method involves a shared private method called validateOrder. While the class seems to have a cohesive responsibility for processing orders, it's potentially violating SRP because changes requested by different stakeholders might affect the overall class. For example, if there are changes to the validated order for warehouse management, these modifications might disrupt validation for the customer and account processing section


Solution - Refactoring with SRP: To address the SRP violation, we break down the OrderProcessor class into 3 separate classes, each catering to a specific business stakeholder:

class CustomerServiceOrderProcessor {
    public void processOrder(...) {
        // ...
        validateOrder(...);
        // ...
    }

    private boolean validateOrder(...) {
        // Validation logic specific to customer service orders
        // ...
        return isValid;
    }
}
class WarehouseOrderProcessor {
    public void processOrder(...) {
        // ...
        validateOrder(...);
        // ...
    }

    private boolean validateOrder(...) {
        // Validation logic specific to warehouse management orders
        // ...
        return isValid;
    }
}
class AccountingOrderProcessor {
    public void processOrder(...) {
        // ...
        validateOrder(...);
        // ...
    }

    private boolean validateOrder(...) {
        // Validation logic specific to accounting orders
        // ...
        return isValid;
    }
}

By partitioning the business logic into distinct classes, each actor now possesses its class. Any alterations made to the validateOrder no longer affect the logic of other business stakeholders.


Common Misconception

The assertion that "A class should have only 1 reason to change" is not universally accurate.

As there are situations where multiple reasons can prompt method modifications. Adhering to this principle could potentially result in an increased class count, which might impact the overall maintainability and readability of the codebase. Therefore, a balanced approach is required to achieve a suitable trade-off between single responsibility and code simplicity.


Conclusion: A class doesn't have to possess only a single public method or business method. While a class can encompass multiple business methods, it's essential that all these methods collectively serve the singular purpose of a specific business entity.