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:
“
Reportformats 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
| Concern | God class | After SRP |
|---|---|---|
| Change email provider | edit the mega-class, risk breaking formatting | edit ReportMailer only |
| Unit test formatting | needs disk + mail server | test ReportFormatter alone |
| Two devs, two features | conflict on one file | work in separate files |
Don’t over-split
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.