Skip to content

SRP - The Single Responsibility Principle

A class should have one reason to change, which really means one group of people who would ask you to change it.

Builds on Coupling and Cohesion

Stage 2core2 min read

The code

package SOLID.SRP.BadCode;

public class Invoice {

    private double amount;

    public Invoice(double amount) {
        this.amount = amount;
    }

    public void generateInvoice() {
        // In real code, this may calculate tax and format the invoice.
        System.out.println("Invoice generated & printed for amount " + amount);
    }

    public void saveToDatabase() {
        // In real code, this may open a connection and run SQL.
        System.out.println("Saving invoice to database");
    }

    public void sendEmailNotification() {
        // In real code, this may use an email provider and a template.
        System.out.println("Sending email notification for invoice");
    }
}

Main creates one Invoice and calls all three methods. The program runs fine, but one class holds three unrelated jobs: making the invoice, saving it and emailing it.

What is wrong

A class should have only one reason to change.

In simple terms, a change for one job should not make you edit code for another job. The key word is actor. An actor is a group of people who ask for the same kind of change. A class should answer to only one actor.

This class looks small only because each method is just a println. Now picture the real method bodies:

  • generateInvoice() would hold GST rules and rounding. Finance asks for those changes.
  • saveToDatabase() would hold JDBC code (Java's database API) and table names. The platform team or DBA asks for those changes.
  • sendEmailNotification() would hold email provider settings and a template. Marketing or CRM asks for those changes.

So one file has three actors and three reasons to change. The problem is not the number of lines. The problem is that three unrelated groups own the same file.

What it costs you

  • Unrelated changes collide. A new email footer and a GST fix edit the same file. They share one review and one deployment.
  • Testing gets costly. To test a tax calculation you may have to set up a database and a mail server, even though the calculation uses neither.
  • Reuse gets awkward. To resend an old invoice email, you must use an Invoice class that also knows about storage.
  • The class keeps growing. PDF export and WhatsApp sharing will probably land here too, because it already holds "invoice stuff."
  • Bugs spread. A harmless formatting edit can break the calculation or saving code right next to it.

Quick test

Describe the class in one sentence: "It builds the invoice and saves it and emails it." The word "and" is a hint, not proof. To confirm, ask who asks for each change. Here finance, platform and marketing are three separate actors, so the jobs should be split.

See GoodCode for the split version, and SRP-Notes.md for the full explanation and trade-offs.

In this topic

Before code2 files

BadCode/Invoice.java26 linesGitHub
package SOLID.SRP.BadCode;public class Invoice {    private double amount;    public Invoice(double amount) {        this.amount = amount;    }    // Additional Functionality    public void generateInvoice() {        System.out.println("Invoice generated & printed for amount " + amount);    }    // this should be different class    public void saveToDatabase() {        System.out.println("Saving invoice to database");    }    // this should be different class    public void sendEmailNotification() {        System.out.println("Sending email notification for invoice");    }}
BadCode/Main.java16 linesGitHub
package SOLID.SRP.BadCode;/** * Bad: Invoice does too much (generate, save, send email). Run this to see the coupled behavior. */public class Main {    @SuppressWarnings("unused")    public static void main(String[] args) {        Invoice invoice = new Invoice(100.0);        invoice.generateInvoice();        invoice.saveToDatabase();        invoice.sendEmailNotification();    }}

Done with this topic?

How well do you know it?

Practise 6 questions