Single Responsibility Principle
Transcript of Single Responsibility Principle
SOLID
Five basic principles of object-oriented programming and design that deals with “dependency management”
● S SRP Single responsibility principle● O OCP Open/closed principle● L LSP Liskov substitution principle● I ISP Interface segregation principle● D DIP Dependency inversion principle
Principles vs. Patterns
A pattern in “is a general reusable solution to a commonly occurring problem within a given context in software design”
● Use a pattern to solve a known problem.● Use the principles to identify the problem and come up
with the solution.
Single Responsibility Principle
“A class should have one and only one reason to change, meaning that a class should have only one job.”
Not responsible for bug fixes or refactoring. Those things are the responsibility of the programmer, not of the program
Then what’s a program responsible to?
First Example
class Employee {
public Money calculatePay()
public void save()
public String reportHours()
}
Three reasons to change:● The business rules having to do with calculating pay.● The database schema.● The format of the hours report.
Step by Step Example
New request has arrived:1. Generate a weekly report of online users2. Send it to Jill in France
1- Monthly instead of weekly
3- Jill gets fired
2- Change report’s format to CSV
Possible Reasons to Change
1- Get a list of users upon a criteria
2- Format the message
3- Deliver the report
Break down:Responsibilities handled in each method in one class
4- Put it all togather
Sketch - Relations
ReportMailer UserWeeklyReport
ReportDataCSVCompiler UserWeeklyReportData
User
Formatting
Parsing users
Getting users
Mail delivery
Report generation
Separation of Concerns
Classes are not the end. Applicable on every level!
It goes back even to the days when Structured Programming was all the hype
Applicable on functions, classes, modules, …
Separation of Concerns
● OOP languages separate concerns into objects
● Architectural design patterns like MVC separate content from presentation and the data-processing (model) from content
● Service-oriented design use services
● Procedural languages such as C use functions.
Method-wise Example
● In a class that handles syncing local data with Dropbox
● Show up an alert view to handle some clashes
● Due to some design limitation, the following method gets called to handle the user’s choice for each alert-alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
Response to “Notepad clashes” alert
Three sub cases!
Response to “older DB” alert
Handle project clashes
Logical separationThe purpose of this method is clear: “switching”
Each of the other three methods handle one case
1
23
We can apply the same here
1
2
3
Examples of “Frequent” Responsibilities
● Persistence to storage● Validation ● Notification ● Error Handling● Logging● Class Selection / Instantiation● Formatting● Parsing● Mapping
How do you know that SRP is violated?
First answer: “Length”
Popular choices:Classes shouldn’t exceed 200 lines of code (exclude comments)Methods shouldn’t exceed 30 lines of code
Is this a solid metric? … Not exactly!
Less than 200 lines of code
Does it follow SRP correctly?
Code to “prepare” for requests performed for Dashboard
Descriptors.Similar to routing
MappingJSON <-> Objects
Various requests performed on Dashboard
Reasons “Mapping” part would change● Web request refactored
● Dashboard needed to be used in another request with different parameters
Encapsulate a single request into a proxy object
Few reasons to make this class change
Biggest benefit: Dashboard is simpler and shorter
Length ??
So length isn’t a very accurate metric.
If a class is higher than 200 loc, then it’s problem!
If it’s fewer than 200 loc, that doesn’t mean you’re clear!
SRP Violation Smells
● Class has too many instance variables and methods○ Especially, when you always use a group of them together
● The test class becomes too complicated○ Too many mock objects○ Too many test cases
● Use “and” or “or” in names● Class with low cohesion
○ Many parts not related to each other
● Class / Method is Long
SRP Violation Smells
● Change In One Place Breaks Another
● Shotgun Effect
● Unable to Encapsulate a Module
● Class has too many dependencies
Why?
● Organize the code
○ So you know where to look for the next request
● Code Changes
○ If you have to refactor one class, only one class will change
● Less fragile
○ “You were only supposed to send an email, how did you end
up deleting all the data?”
Why?
● Testability○ Less test cases for a class with one job to do
● Code sharing○ All previous reasons are equally or more important than this
one!○ Don’t wait till you have to reuse the code, start breaking
down your code when it makes sense.
Complex view example
A controller that populates a table view and a charts area with data retrieved from another object
Data source to ChartsEngine: Provides needed content to the object that draws the charts~ 50 lines
Source to the side table view~ 40 lines
Another responsibility: Provide a widget builder so other object can use it build it.
Get data and show it in view
Add a couple of lines to initialize those helpers and provide data to them
And the view controller drops to ~ 100 lines of total code
One clear responsibility: Get data from a data loader object and provide to “view source” object
We didn’t handle that yet! But you get the picture...
Correlation with Frameworks
Sometimes, the way the framework is designed makes it easy to put all your code in one place
● iOS: View controllers and application delegates
● Android: Activities
● RoR: ActiveRecord models
Monster AppDelegate - Example Responsibilities
● Receive application’s notifications● Register for a 3rd party service● Handle global view settings● Show notification for version updates and handle
user’s action● Dropbox connection● Handle push notifications
Example Patterns to Decompose Fat Classes
● Standard composition / Delegation○ Two basic design patterns○ Break a complex class into smaller ones
● View objects / View model / Presenter○ If some logic is needed to prepare the model for view
● Decorator○ Put the extra behaviour in a new class
● Specific patterns to specific problems○ e.g. Factory / Builder for object creation
References1. The Principles of OOD (Uncle Bob)2. SOLID (Wikipedia)3. Software Design Pattern (Wikipedia)4. Uncle Bob (blog.8thlight.com)5. Ruby Example (John Bohn)6. Separation of Concerns (Wikipedia)7. Examples of Responsiblities (deviq.com)8. Why SRP and SRP Smells (Java Code Geeks)9. Fat ActiveRecord Models (blog.codeclimate.com)
10. Active Record Breaks SRP by Design (sitepoint.com) 11. Active Record Breaks SRP by Design (programmers.stackexchange)12. Patterns to Destroy Big View Controllers (Soroush Khanlou)