The Single Responsibility Principle says:
A module should have one reason to change.
In practice, this means code used by different groups of people should usually be separated. Each group may ask for different changes, and one group’s change should not accidentally break another group’s behavior.
Example
Suppose HR and Finance both use the same payroll function:
def calculate_pay(hours_worked, hourly_rate):
overtime_hours = max(hours_worked - 40, 0)
regular_hours = min(hours_worked, 40)
return (regular_hours * hourly_rate) + (overtime_hours * hourly_rate * 1.5)This looks fine while HR and Finance agree on the overtime rule. But if HR later says overtime should count as 1.0x for an internal report, changing this function would also affect Finance’s actual payroll calculation.
That function now has two reasons to change:
- HR reporting rules change.
- Finance payment rules change.
Better:
def calculate_finance_pay(hours_worked, hourly_rate):
overtime_hours = max(hours_worked - 40, 0)
regular_hours = min(hours_worked, 40)
return (regular_hours * hourly_rate) + (overtime_hours * hourly_rate * 1.5)
def calculate_hr_reported_pay(hours_worked, hourly_rate):
overtime_hours = max(hours_worked - 40, 0)
regular_hours = min(hours_worked, 40)
return (regular_hours * hourly_rate) + (overtime_hours * hourly_rate * 1.0)Now each function has one reason to change. Finance can change payroll rules without affecting HR reports, and HR can change reporting rules without affecting payroll.
SRP is not about making every function tiny. It is about separating code when different actors depend on it for different reasons.