Embracing the Single Responsibility Principle in Real Engineering

Ravi Chandola
Javarevisited
Published in
3 min readMar 12, 2024

The Single Responsibility Principle (SRP), a concept in object-oriented programming, is akin to the old adage “Too many cooks spoil the broth”. In the realm of coding, the SRP espouses the view that each class or module should have a single, well-defined role or task. It is one of the five tenets of the SOLID principles, which are widely recognized good practices in software engineering.

Imagine you’re a chef in a kitchen. You have different tools for different tasks — a knife for cutting, a spoon for stirring, a grater for shredding. Now, suppose there was a tool that claimed to do all these tasks. It might seem like a great idea initially — a single tool to replace multiple others. However, you soon realize that it’s not as efficient or effective as the individual tools were. It doesn’t cut as well as the knife, nor stir as well as the spoon. This is what happens when a class in coding takes on too many responsibilities.

Applying the SRP, each class would focus on a single task. Just like in the kitchen where each tool is designed for a specific task, and performs that task very well, in software engineering, a class with a single responsibility would be more efficient and effective.

For instance, in a payroll system, instead of having a single ‘Employee’ class that calculates pay, prints a paycheck, and writes the check details to a database, you would divide these responsibilities into separate classes: ‘PayCalculator’, ‘PaycheckPrinter’, and ‘PaycheckDatabaseWriter’. Each class would have one reason to change — a change in pay calculation rules would only affect ‘PayCalculator’, not the other two classes.

Let’s consider a simple example in Javascript:

Without using the Single Responsibility Principle:

class Employee {
constructor(name, hours, rate) {
this.name = name;
this.hours = hours;
this.rate = rate;
}

calculatePay() {
return this.hours * this.rate;
}

printPaycheck() {
const pay = this.calculatePay();
console.log(`Paycheck for ${this.name}: ${pay}`);
}
}

const employee = new Employee('Ravi Chandola', 40, 20);
employee.printPaycheck();

In the above code, the Employee class is responsible for both calculating the pay and printing the paycheck, which are two different responsibilities.

Now, let’s refactor the above code using the Single Responsibility Principle:

class PayCalculator {
constructor(hours, rate) {
this.hours = hours;
this.rate = rate;
}

calculatePay() {
return this.hours * this.rate;
}
}

class PaycheckPrinter {
printPaycheck(name, pay) {
console.log(`Paycheck for ${name}: ${pay}`);
}
}

class Employee {
constructor(name, hours, rate) {
this.name = name;
this.payCalculator = new PayCalculator(hours, rate);
this.paycheckPrinter = new PaycheckPrinter();
}

issuePaycheck() {
const pay = this.payCalculator.calculatePay();
this.paycheckPrinter.printPaycheck(this.name, pay);
}
}

const employee = new Employee('Ravi Chandola', 40, 20);
employee.issuePaycheck();

In this refactored code, we have created two separate classes: PayCalculator and PaycheckPrinter. Each class is now handling a single responsibility. The PayCalculator class is responsible for calculating the pay, while the PaycheckPrinter class is responsible for printing the paycheck. The Employee class now acts as a coordinator that uses the PayCalculator to calculate the pay and then passes the result to the PaycheckPrinter to print the paycheck. This separation of responsibilities makes the code more maintainable and easier to test, which is the main benefit of the Single Responsibility Principle.

The benefits of the SRP are manifold:

  1. Simplicity and Clarity: When each class has a single job, it’s easier to understand and explain what that class does. It becomes more readable and manageable.
  2. Ease of Testing: It’s simpler to write tests for a class that does one thing. This also means that the tests are less likely to break in the future.
  3. Reduced Risk of Bugs: Changes in one class are less likely to affect others, reducing the risk of introducing bugs.
  4. Improved Flexibility: With responsibilities neatly divided, it’s easier to update or add functionalities. You can modify or extend the behavior of a single responsibility without touching other parts of the code.

In the end we can say that, the Single Responsibility Principle is an effective strategy in software engineering that promotes clarity, efficiency, and robustness in code. By ensuring that each class or module has a singular focus, developers can create systems that are easier to maintain, understand, and expand, making the SRP a good practice worth embracing.

--

--

Ravi Chandola
Javarevisited

As a technology enthusiast, I have a passion for learning and sharing my knowledge with others. https://www.linkedin.com/in/ravi-chandola-304522133