A class calculates salary, saves it to the database and prints a payslip. How does it break SRP, and how do you fix it?
It has three reasons to change: pay rules, database layout and payslip format. Split it into three classes, each with one job, and let a small coordinator call them.
Explain it simply
A shop owner who also cooks, delivers and does the accounts will struggle whenever any one of those jobs changes. In code, a class that mixes business rules, storage and presentation is touched by three different people for three different reasons, and each edit risks breaking the other two.
Example
# Before: one class, three reasons to change
class Payroll:
def net(self, basic): return basic - basic * 0.1
def save(self, emp, amount): ... # SQL lives here
def payslip(self, emp, amount): ... # formatting lives here
# After: one job each
class SalaryCalculator:
def net(self, basic): return basic - basic * 0.1
class SalaryRepository:
def save(self, emp, amount): ...
class PayslipPrinter:
def render(self, emp, amount): return f"{emp}: Rs {amount}"
def run_payroll(emp, basic, calc, repo, printer):
amount = calc.net(basic)
repo.save(emp, amount)
return printer.render(emp, amount)A change in tax rules now touches SalaryCalculator only. Tests for it need no database.
What to say in the interview
"The class mixes calculation, persistence and presentation, so it changes for three reasons. I split those into separate classes and compose them. Each is smaller, easier to test, and changes independently."
Common mistakes
- Splitting so far that one simple feature needs ten tiny classes.