Before you start
Welcome to SOLID. Five design principles named by Robert Martin ("Uncle Bob"). They put words to the habits you'll lean on for the rest of your career.
S — Single Responsibility Principle (this lesson) O — Open/Closed Principle L — Liskov Substitution Principle I — Interface Segregation Principle D — Dependency Inversion Principle
Every principle has the same shape: spot the smell, apply the fix, feel the difference. Today: SRP.
The exact definition
Uncle Bob's version: "A class should have one, and only one, reason to change."
The important word is change. Not "does one thing" — that's vague. Reason to change is concrete: if two different teams would both want to edit this class for their own reasons, it has too many jobs.
The Invoice example, step by step
The god class in the objective has four reasons to change:
| What triggers a change | Which method changes |
|---|---|
| Add tax | total() |
| HTML receipts | format_text() |
| Move to S3 | save_to_file() |
| Switch email provider | email() |
Four different teams, all editing the same file every quarter. Every quarter, one team's change accidentally breaks another team's tests. This is what SRP prevents.
After the fix:
| What triggers a change | Which class changes |
|---|---|
| Add tax | Invoice |
| HTML receipts | InvoiceFormatter |
| Move to S3 | InvoiceRepository |
| Switch email provider | InvoiceMailer |
Four unrelated classes, four unrelated teams, no more conflicts.
Why this matters in design interviews
Every design problem you meet has a hidden god class temptation. The person who writes:
class ParkingLot:
def park(self, ...): ...
def unpark(self, ...): ...
def calculate_fee(self, ...): ...
def send_receipt(self, ...): ...
def report_occupancy(self, ...): ...
def log_to_audit(self, ...): ...
is missing SRP. The person who says "these are separate
concerns — FeeCalculator, Receipt, OccupancyReport,
AuditLog" is showing the design maturity interviewers
reward.
About the "delegates to" tests
Two of the tests in this lesson check that Repository and Mailer actually USE the Formatter, instead of writing the format themselves. That's the SRP shape: one place to change the format, one place to change how we save, one place to change how we send. If any of them copies another's logic, you've re-created the god class in a slightly bigger package.