Single Responsibility Principle
Also related: Separation of Concerns
Intent
A class should have one primary reason to change. Put different kinds of work in different places.
Responsibility ≈ a reason the class would need to change — not “number of methods.”
Problem
You start a simple Journal: add entries, remove them, print them. Then someone asks to save to disk. You add save() on the same class.
Now the class changes when entry rules change and when file format or I/O changes. Two reasons. Testing and reuse get harder.
Solution
Keep Journal focused on entries. Move persistence to PersistenceManager.
That second class is the fix, not the violation.
Structure
| Class | Responsibility | Methods |
|---|---|---|
Journal | Manage diary entries | add_entry, remove_entry, __str__ |
PersistenceManager | Write a journal to disk | save_to_file |
Compare code
Violation — persistence inside Journal
python
class Journal:
def add_entry(self, text): ...
def remove_entry(self, index): ...
def save(self, filename): # second responsibility
with open(filename, "w") as f:
f.write(str(self))Compliant — this repo
python
class Journal:
def add_entry(self, text): ...
def remove_entry(self, index): ...
# no save / load here
class PersistenceManager:
@staticmethod
def save_to_file(journal, filename):
with open(filename, "w") as f:
f.write(str(journal))Walkthrough
Quick check
In the compliant example, which statement is true?
Run locally
bash
uv run srpSource: main.py · tutorial README
Takeaway
- Domain object → business data and behavior
- Persistence helper → how that data is stored
- Mixing them couples your model to the filesystem