View
8
Download
1
Category
Preview:
DESCRIPTION
We’ve all heard about well-designed software projects, where things aren’t (yet) a big ball of mud that’s painful to work with, but many of us aren’t lucky enough to work on these. Nor is it an option for us to get to start a brand new “greenfield” project, where we can leave behind the legacy of spaghetti code and technical debt our current project might have. But there is hope! By applying refactoring steps based on SOLID principles of object oriented design, we can reduce the technical debt of our existing application, improve our code quality, and hopefully make our application more enjoyable and productive to work with. In this session, we’ll briefly introduce the SOLID principles and several design patterns, and then we’ll apply these principles and patterns by improving the design of an existing application through several refactoring steps.
Citation preview
Follow me at twitter.com/ardalis
Refactoring Applicationsusing SOLID Principles
Steve SmithTelerik
ardalis.com @ardalis
Follow me at twitter.com/ardalis
Coming Soon: Refactoring Fundamentals
Follow me at twitter.com/ardalis
Software Rots
How? Duplication Excess Coupling Quick Fixes Hacks
Follow me at twitter.com/ardalis
Preventive Maintenance
• Refactoring– Eliminate Duplication– Simplify Design
• Automated Tests– Verify correctness– Avoid regressions– Increase Confidence
Follow me at twitter.com/ardalis
Refactoring Process
• Verify existing behavior• Write Characterization Tests if none
exist– Find test points– Break dependencies
• Apply Refactoring• Confirm existing behavior is
preserved
Follow me at twitter.com/ardalis
Characterization Tests
Process1. Write a test you know will fail2. 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
S O L I DPrinciples
http://flickr.com/photos/kevinkemmerer/2772526725/
Follow me at twitter.com/ardalis
Principles of OO Design
0. Don’t Repeat Yourself (DRY)
1.Single Responsibility2.Open/Closed3.Liskov Substitution4.Interface Segregation5.Dependency Inversion
Follow me at twitter.com/ardalis
Don’t RepeatRepeat Yourself
• Duplication in logic calls for abstraction
• Duplication in process calls for automation
Follow me at twitter.com/ardalis
Common Refactorings
• Replace Magic Number/String• Parameterize Method• Pull Up Field• Pull Up Method• Replace Conditional With
Polymorphism• Introduce Method
Follow me at twitter.com/ardalis
Role Checksif(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}
Follow me at twitter.com/ardalis
Single Responsibility PrincipleThe 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
Follow me at twitter.com/ardalis
Example Responsibilities
• Persistence• Validation• Notification• Error Handling• Logging• Class Selection / Construction• Formatting• Parsing• Mapping
Follow me at twitter.com/ardalis
Dependency and Coupling
• Excessive coupling makes changing legacy software difficult
• Breaking apart responsibilities and dependencies is a large part of working with existing code
Follow me at twitter.com/ardalis
Common Refactorings
• Extract Class• Move Method
Follow me at twitter.com/ardalis
Heuristics and Code Smells
• Visual Studio Metrics
Follow me at twitter.com/ardalis
Code Smell: Regions
?More on Regions: http://ardalis.com/regional-differences
Follow me at twitter.com/ardalis
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
Follow me at twitter.com/ardalis
Open / Closed Principle
Open to ExtensionNew behavior can be added in the future
Closed to ModificationChanges to source or binary code are not required
Dr. Bertrand Meyer originated the OCP term in his 1988 book, Object Oriented Software Construction
Follow me at twitter.com/ardalis
Common Refactorings
• Extract Interface / Apply Strategy Pattern
• Parameterize Method• Form Template Method
Follow me at twitter.com/ardalis
OCP Fail
Follow me at twitter.com/ardalis
OCP OK
Follow me at twitter.com/ardalis
OCP Failpublic bool IsSpecialCustomer(Customer c){ if(c.Country == “US” && c.Balance < 50) return false; if(c.Country == “DE” && c.Balance < 25) return false; if(c.Country == “UK” && c.Balance < 35) return false; if(c.Country == “FR” && c.Balance < 27) return false; if(c.Country == “BG” && c.Balance < 29) return false;
if(c.Age < 18 || c.Age > 65) return false; if(c.Income < 50000 && c.Age < 30) return false; return true;}
Follow me at twitter.com/ardalis
OCP OKprivate IEnumerable<ICustomerRule> _rules;
public bool IsSpecialCustomer(Customer c){ foreach(var rule in _rules) { if(rule.Evaluate(c) == false) return false; } return true;}
Follow me at twitter.com/ardalis
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.
Follow me at twitter.com/ardalis
Common Refactorings
• Collapse Hierarchy• Pull Up / Push Down Field• Pull Up / Push Down Method
Follow me at twitter.com/ardalis
Liskov Substitution Failforeach(var employee in employees){ if(employee is Manager) { Helpers.PrintManager(employee as Manager); break; } Helpers.PrintEmployee(employee);}
Follow me at twitter.com/ardalis
Liskov Substitution OKforeach(var employee in employees){ employee.Print(); // or Helpers.PrintEmployee(employee);}
Follow me at twitter.com/ardalis
Interface Segregation PrincipleThe 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
Follow me at twitter.com/ardalis
Common Refactorings
• Extract Interface
Follow me at twitter.com/ardalis
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);}
Follow me at twitter.com/ardalis
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);}
Follow me at twitter.com/ardalis
Dependency Inversion PrincipleHigh-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#
Follow me at twitter.com/ardalis
Dependency Inversion Principle• Depend on Abstractions– Interfaces, not concrete types
• Inject Dependencies into Classes
• Structure Solution so Dependencies Flow Toward Core– Onion Architecture
Follow me at twitter.com/ardalis
Application Layers
Follow me at twitter.com/ardalis
Data Access EvolutionNo separation of concerns:
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
User Interface
Database
Compile Time
Runtime
Follow me at twitter.com/ardalis
Data Access : Helper Classes Calls to data made through
a utility
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
User Interface
Database
Compile Time
Runtime
Helper Class
Follow me at twitter.com/ardalis
What’s Missing? Abstraction! No way to abstract
away data access
Tight coupling
Leads to Big Ball of Mud system
Solution: Depend on interfaces, not
concrete implementations What should we call such
interfaces? Repositories!
User Interface
Database
Compile Time
Runtime
CoreIFooRepository
InfrastructureSqlFooRepository
Follow me at twitter.com/ardalis
DIP “Onion” Architecture
Follow me at twitter.com/ardalis
Common Dependencies
• Framework• Third Party Libraries• Database• File System• Email• Web Services• System Resources (Clock)• Configuration• The new Keyword• Static methods• Thread.Sleep• Random
See also responsibilities:• Persistence• Validation• Notification• Error Handling• Logging• Class Selection /
Construction• Formatting• Parsing• Mapping
Follow me at twitter.com/ardalis
Common Refactorings
• Extract Class• Extract Interface / Apply Strategy
Pattern• Extract Method• Introduce Service Locator / Container
Follow me at twitter.com/ardalis
DIP Fail
Follow me at twitter.com/ardalis
Some Improvement (Façade)
Follow me at twitter.com/ardalis
DIP OK (Strategy)
Follow me at twitter.com/ardalis
DIP OK (Strategy)
Follow me at twitter.com/ardalis
Summary
• Maintain / Improve Application Code• Follow DRY/SOLID Principles• Use Characterization Tests to “fix”
behavior• Apply Common Refactorings• Re-run Tests After (and during)
Refactorings
Follow me at twitter.com/ardalis
References
Principles of Object Oriented Design (Pluralsight) http://bit.ly/SFkpmq
Refactoring Catalog http://www.refactoring.com/catalog/index.html
Onion Architecture http://jeffreypalermo.com/blog/the-onion-architecture-pa
rt-1/
Follow me at twitter.com/ardalis
Books Refactoring http
://amzn.to/110tscA Refactoring to Patterns
http://amzn.to/Vq5Rj2 Working Effectively with
Legacy Code http://amzn.to/VFFYbn
Code Complete http://amzn.to/Vq5YLv
Clean Code http://amzn.to/YjUDI0
Follow me at twitter.com/ardalis
Thank You!
Find Me Online:Blog: http://ardalis.comTwitter: @ardalishttp://facebook.com/StevenAndrewSmith
Follow me at twitter.com/ardalis
Discussion
Recommended