Back to the path
Level 2 intermediate 25 min #solid#principles#design

Single Responsibility Principle (SRP)

The S in SOLID: a class should have one reason to change. Learn to spot 'God classes' and split them cleanly.

One reason to change

“A class should have one, and only one, reason to change.” — Robert C. Martin

SRP is the most misquoted SOLID principle. It does not mean “a class does one thing” or “keep classes tiny.” It means a class should answer to one stakeholder / one axis of change. If the marketing team’s email rules and the database team’s storage rules can both force you to edit the same class, that class has two reasons to change — it violates SRP.

Spotting a God class

A “God class” accumulates responsibilities until everything routes through it. The tell-tale sign is the word “and” in its description:

Report formats the data and writes the file and emails it.”

Three ands = three responsibilities = three reasons to change, all tangled together. Symptoms you’ll feel:

  • A change to email logic forces a re-test of formatting (they share a class).
  • You can’t unit-test formatting without a mail server and a disk.
  • Merge conflicts: three different people edit this one file for three unrelated reasons.

The refactor: split, then compose

Pull each responsibility into its own focused class, then let a thin coordinator compose them:

class ReportFormatter { toHtml(data: Data): string { /* ... */ } }
class ReportStorage   { save(html: string): void { /* ... */ } }
class ReportMailer    { email(html: string): void { /* ... */ } }

// Coordinator — its single responsibility is the *workflow*, not the details.
class ReportService {
constructor(
  private formatter: ReportFormatter,
  private storage: ReportStorage,
  private mailer: ReportMailer,
) {}
publish(data: Data) {
  const html = this.formatter.toHtml(data);
  this.storage.save(html);
  this.mailer.email(html);
}
}

Notice this is composition over inheritance (Level 0) doing real work: ReportService has-a formatter, storage, and mailer.

Why this pays off

ConcernGod classAfter SRP
Change email provideredit the mega-class, risk breaking formattingedit ReportMailer only
Unit test formattingneeds disk + mail servertest ReportFormatter alone
Two devs, two featuresconflict on one filework in separate files

Don’t over-split

Watch out

SRP taken to an extreme gives you 200 one-line classes and a navigation nightmare. The judgment call is: “Do these things change for the same reason?” If yes, they belong together. If they change for different reasons or at the request of different people, separate them.

That judgment — not memorizing the definition — is what interviewers probe. The design problem below is a textbook God class; refactor it before peeking at the reference.

Assessment

Pass mark: 70% on the concept questions unlocks the next lesson.

1. The cleanest statement of SRP is:

2. A `Report` class formats data to HTML, AND saves it to disk, AND emails it. Why does this violate SRP? (select all) (select all)

3. After splitting the God class, how do the pieces usually collaborate?

Design problem 4

Refactor this God class: class UserService { registerUser(data) { /* validate, hash password, save to DB, send welcome email, log */ } } List the responsibilities, split them, and show how they're wired together.