Transcript Document

Refactoring Applications
using SOLID Principles
Steve Smith
Telerik
ardalis.com @ardalis
www.devreach.com
Software Rots
How?
 Duplication
 Excess Coupling
 Quick Fixes
 Hacks
www.devreach.com
Preventive Maintenance
• Refactoring
– Eliminate Duplication
– Simplify Design
• Automated Tests
– Verify correctness
– Avoid regressions
– Increase Confidence
www.devreach.com
Refactoring Process
• Verify existing behavior
• Write Characterization Tests if none exist
– Find test points
– Break dependencies
• Apply Refactoring
• Confirm existing behavior is preserved
www.devreach.com
Characterization Tests
Process
1. Write a test you know will fail
2. Use the output of the failing test to
determine the existing behavior to assert
3. Update the test with the new
value/behavior
4. Run the test again – it should pass
www.devreach.com
SOLID
Principles
http://flickr.com/photos/kevinkemmerer/2772526725
Principles of OO Design
0. Don’t Repeat Yourself (DRY)
1. Single Responsibility
2. Open/Closed
3. Liskov Substitution
4. Interface Segregation
5. Dependency Inversion
www.devreach.com
Don’t Repeat
Repeat Yourself
• Duplication in logic calls for abstraction
• Duplication in process calls for
automation
www.devreach.com
Common Refactorings
•
•
•
•
•
•
Replace Magic Number/String
Parameterize Method
Pull Up Field
Pull Up Method
Replace Conditional With Polymorphism
Introduce Method
www.devreach.com
Role Checks
if(user.IsInRole(“Admins”)
{
// allow access to resource
}
// favor privileges over role checks
// ardalis.com/Favor-Privileges-over-Role-Checks
var priv = new ContentPrivilege(user, article);
if(priv.CanEdit())
{
// allow access
}
www.devreach.com
Single Responsibility Principle
The Single Responsibility Principle states that every object
should have a single responsibility, and that
responsibility should be entirely encapsulated by the
class.
Wikipedia
There should never be more than one reason for a class to
change.
Robert C. “Uncle Bob” Martin
www.devreach.com
Example Responsibilities
•
•
•
•
•
•
•
•
•
Persistence
Validation
Notification
Error Handling
Logging
Class Selection / Construction
Formatting
Parsing
Mapping
www.devreach.com
Dependency and Coupling
• Excessive coupling makes changing
legacy software difficult
• Breaking apart responsibilities and
dependencies is a large part of working
with existing code
www.devreach.com
Common Refactorings
• Extract Class
• Move Method
www.devreach.com
Heuristics and Code Smells
• Visual Studio Metrics
www.devreach.com
Code Smell: Regions
More on Regions: http://ardalis.com/regional-differences
www.devreach.com
Open / Closed Principle
The Open / Closed Principle states that software entities
(classes, modules, functions, etc.) should be open for
extension, but closed for modification.
Wikipedia
www.devreach.com
Open / Closed Principle
Open to Extension
New behavior can be added in the future
Closed to Modification
Changes to source or binary code are not required
Dr. Bertrand Meyer originated the OCP term in his 1988
book, Object Oriented Software Construction
www.devreach.com
Common Refactorings
• Extract Interface / Apply Strategy Pattern
• Parameterize Method
• Form Template Method
www.devreach.com
OCP Fail
www.devreach.com
OCP Fail
public bool IsSpecialCustomer(Customer c)
{
if(c.Country == “US” && c.Balance < 50)
if(c.Country == “DE” && c.Balance < 25)
if(c.Country == “UK” && c.Balance < 35)
if(c.Country == “FR” && c.Balance < 27)
if(c.Country == “BG” && c.Balance < 29)
return
return
return
return
return
false;
false;
false;
false;
false;
if(c.Age < 18 || c.Age > 65) return false;
if(c.Income < 50000 && c.Age < 30) return false;
return true;
}
www.devreach.com
OCP OK
private IEnumerable<ICustomerRule> _rules;
public bool IsSpecialCustomer(Customer c)
{
foreach(var rule in _rules)
{
if(rule.Evaluate(c) == false) return false;
}
return true;
}
www.devreach.com
Liskov Substitution Principle
The Liskov Substitution Principle states that
Subtypes must be substitutable for their
base types.
Agile Principles, Patterns, and Practices in
C#
Named for Barbara Liskov, who first
described the principle in 1988.
www.devreach.com
Common Refactorings
• Collapse Hierarchy
• Pull Up / Push Down Field
• Pull Up / Push Down Method
www.devreach.com
Liskov Substitution Fail
foreach(var employee in employees)
{
if(employee is Manager)
{
Helpers.PrintManager(employee as Manager);
break;
}
Helpers.PrintEmployee(employee);
}
www.devreach.com
Liskov Substitution OK
foreach(var employee in employees)
{
employee.Print();
// or
Helpers.PrintEmployee(employee);
}
www.devreach.com
Interface Segregation Principle
The Interface Segregation Principle states that
Clients should not be forced to depend on
methods they do not use.
Agile Principles, Patterns, and Practices in C#
Corollary:
Prefer small, cohesive interfaces to “fat” interfaces
www.devreach.com
Common Refactorings
• Extract Interface
www.devreach.com
ISP Fail (sometimes)
public IRepository<T>
{
T GetById(int id);
IEnumerable<T> List();
void Create(T item);
void Update(T item);
void Delete(T item);
}
www.devreach.com
ISP OK (for CQRS for example)
public IRepository<T> : IReadRepository<T>,
IWriteRepository<T>
{ }
public IReadRepository<T>
{
T GetById(int id);
IEnumerable<T> List();
}
public IWriteRepository<T>
void Create(T item);
void Update(T item);
void Delete(T item);
}
www.devreach.com
Dependency Inversion Principle
High-level modules should not depend on low-level
modules. Both should depend on abstractions.
Abstractions should not depend on details. Details
should depend on abstractions.
Agile Principles, Patterns, and Practices in C#
www.devreach.com
Dependency Inversion Principle
• Depend on Abstractions
– Interfaces, not concrete types
• Inject Dependencies into Classes
• Structure Solution so Dependencies Flow
Toward Core
– Onion Architecture
www.devreach.com
Application Layers
www.devreach.com
Data Access Evolution
Compile Time
Runtime
No separation of concerns:
User Interface
 Data access logic baked directly into UI
 ASP.NET Data Source Controls
 Classic ASP scripts
 Data access logic in UI layer via codebehind
 ASP.NET Page_Load event
 ASP.NET Button_Click event
Database
www.devreach.com
Data Access : Helper
Classes
Compile Time
Runtime
 Calls to data made through a
utility
User Interface
 Example: Data Access
Application Block (SqlHelper)
 Logic may still live in UI layer
 Or a Business Logic Layer may
make calls to a Data Access
Layer which might then call the
helper
www.devreach.com
Helper Class
Database
What’s Missing? Abstraction!
Compile Time
Runtime
 No way to abstract away
data access
User Interface
 Tight coupling
 Leads to Big Ball of Mud
system
Core
IFooRepository
Infrastructure
SqlFooRepository
 Solution:
 Depend on interfaces, not
concrete implementations
 What should we call such
interfaces? Repositories!
www.devreach.com
Database
DIP “Onion” Architecture
www.devreach.com
Common Dependencies
•
•
•
•
•
•
•
•
•
•
•
•
Framework
Third Party Libraries
Database
File System
Email
Web Services
System Resources (Clock)
Configuration
The new Keyword
Static methods
Thread.Sleep
Random
www.devreach.com
See also responsibilities:
• Persistence
• Validation
• Notification
• Error Handling
• Logging
• Class Selection /
Construction
• Formatting
• Parsing
• Mapping
Common Refactorings
•
•
•
•
Extract Class
Extract Interface / Apply Strategy Pattern
Extract Method
Introduce Service Locator / Container
www.devreach.com
DIP Fail
www.devreach.com
Some Improvement (Façade)
www.devreach.com
DIP OK (Strategy)
www.devreach.com
DIP OK (Strategy)
www.devreach.com
Summary
• Maintain / Improve Application Code
• Follow DRY/SOLID Principles
• Use Characterization Tests to “fix”
behavior
• Apply Common Refactorings
• Re-run Tests After Refactorings
www.devreach.com
References
 Principles of Object Oriented Design (Pluralsight)
 http://bit.ly/SFkpmq
 Refactoring Catalog
 http://www.refactoring.com/catalog/index.html
 Working Effectively with Legacy Code (Book)
 Michael C. Feathers
 Onion Architecture
 http://jeffreypalermo.com/blog/the-onion-architecture-part-1/
www.devreach.com
Thank You! – Благодаря!
Find Me Online:
Blog: http://ardalis.com
Twitter: @ardalis
http://facebook.com/StevenAndrewSmith
www.devreach.com
Discussion
www.devreach.com