Previously, we discovered how the Single Responsibility Principle (SRP), one of the SOLID Principles, instructs us on how we should and shouldn’t write our classes.
I reused the canonical example from Robert C. Martin’s excellent book ‘Clean Architecture‘: We have an Employee class in a payroll application responsible to three separate ‘actors‘—the IT, Accounting and Operations departments. And herein lay the problem—any changes to the Employee class made by one of the departments might be at odds with the needs of one of the other departments. A modification of a shared helper method by the programmers in Accounting consequently broke expected behaviour in the Operations department.
SRP violations can express themselves as subtle, damaging bugs.
What are we to do? How do we fix this?
Let’s refresh our minds of what the (restated) SRP was about:
Each module should only be responsible to one actor.
How do we make class Employee responsible to only one actor? We may need to break it up into smaller classes, each solely accountable to a single department’s needs.
How should we go about this?
Well, the public methods of Employee are CalculatePay(), ReportHours() and Save(). Each is responsible to a different actor—the Accounting, Operations and IT departments, respectively.
It makes sense to break up Employee along these identified responsibilities, the public methods. But what should we name the new classes?
The names of modules should reflect the work that they do. In our case, it would make sense to have, say, a PayCalculator, an HoursReporter and an EmployeeSaver. Those names are pretty good, I think. No?
Aside – No Noise Words
Please, please give your classes descriptive names that leave out meaningless noise words. Consider PayCalculationHelper, HoursReportManager and EmployeeSavingService. Do these names convey more information than PayCalculator, HoursReporter and EmployeeSaver? No, not really. Their wishy-washy naming reduces clarity and obscures meaning. Indeed, these unclear names may, over time, attract code that does not strictly belong. The often-used ‘Helper‘, ‘Manager‘ and ‘Service‘ noise words detract rather than clarify a classes purpose and are best left out.
The classes after breaking up of class Employee:
A couple of salient points:
Notice that PayCalculator and HoursReporter each have their own, independent version of GetRegularHours(). We got into trouble because a change to GetRegularHours() by the Accounting department broke expected behaviour in Operations. Both PayCalculator and HoursReporter now have separate, independently changeable copies of GetRegularHours(). The Accounting and Operations departments calculate regular employee hours worked differently. We are forgoing DRY (Don’t Repeat Yourself) because it is appropriate, even required, for us to do so.
Our new collection of classes must not reference and call one another. If they do, then we will have re-established the original SRP violation.
The Single Responsibility Principle (Part 2)
/by Olaf ThielkeThe Single Responsibility Principle
(Part 2)
Previously, we discovered how the Single Responsibility Principle (SRP), one of the SOLID Principles, instructs us on how we should and shouldn’t write our classes.
I reused the canonical example from Robert C. Martin’s excellent book ‘Clean Architecture‘: We have an
Employee
class in a payroll application responsible to three separate ‘actors‘—the IT, Accounting and Operations departments. And herein lay the problem—any changes to theEmployee
class made by one of the departments might be at odds with the needs of one of the other departments. A modification of a shared helper method by the programmers in Accounting consequently broke expected behaviour in the Operations department.SRP violations can express themselves as subtle, damaging bugs.
What are we to do? How do we fix this?
Let’s refresh our minds of what the (restated) SRP was about:
How do we make class
Employee
responsible to only one actor? We may need to break it up into smaller classes, each solely accountable to a single department’s needs.How should we go about this?
Well, the public methods of
Employee
areCalculatePay()
,ReportHours()
andSave()
. Each is responsible to a different actor—the Accounting, Operations and IT departments, respectively.It makes sense to break up
Employee
along these identified responsibilities, the public methods. But what should we name the new classes?The names of modules should reflect the work that they do. In our case, it would make sense to have, say, a
PayCalculator
, anHoursReporter
and anEmployeeSaver
. Those names are pretty good, I think. No?Aside – No Noise Words
Please, please give your classes descriptive names that leave out meaningless noise words. Consider
PayCalculationHelper
,HoursReportManager
andEmployeeSavingService
. Do these names convey more information thanPayCalculator
,HoursReporter
andEmployeeSaver
? No, not really. Their wishy-washy naming reduces clarity and obscures meaning. Indeed, these unclear names may, over time, attract code that does not strictly belong. The often-used ‘Helper
‘, ‘Manager
‘ and ‘Service
‘ noise words detract rather than clarify a classes purpose and are best left out.The classes after breaking up of class
Employee
:A couple of salient points:
PayCalculator
andHoursReporter
each have their own, independent version ofGetRegularHours()
. We got into trouble because a change toGetRegularHours()
by the Accounting department broke expected behaviour in Operations. BothPayCalculator
andHoursReporter
now have separate, independently changeable copies ofGetRegularHours()
. The Accounting and Operations departments calculate regular employee hours worked differently. We are forgoing DRY (Don’t Repeat Yourself) because it is appropriate, even required, for us to do so.Further reading: