Transcript Document

Improving the Quality of
Existing Software
Steve Smith
Telerik
ardalis.com @ardalis
Software Rots
Technical Debt
• Low quality code and
shortcuts in our
applications
• Technical debt, like real
debt, has direct cost and
interest
http://www.jimhighsmith.com/
Preventive Maintenance
• Refactoring
– Eliminate Duplication
– Simplify Design
• Automated Tests
– Verify correctness
– Avoid regressions
– Increase Confidence
When should you refactor?
• While delivering value
Refactoring Should Not Change
System Behavior
Refactoring Process
• Verify existing behavior
• Write Characterization Tests if none exist
– Find test points
– Break dependencies
• Apply Refactoring
• Confirm existing behavior is preserved
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
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
Don’t Repeat
Repeat Yourself
• Duplication in logic calls for abstraction
• Duplication in process calls for
automation
Common Refactorings
•
•
•
•
•
•
Replace Magic Number/String
Parameterize Method
Pull Up Field
Pull Up Method
Replace Conditional With Polymorphism
Introduce Method
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
}
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
Example Responsibilities
•
•
•
•
•
•
•
•
•
Persistence
Validation
Notification
Error Handling
Logging
Class Selection / Construction
Formatting
Parsing
Mapping
Dependency and Coupling
• Excessive coupling makes changing
legacy software difficult
• Breaking apart responsibilities and
dependencies is a large part of working
with existing code
Common Refactorings
• Extract Class
• Extract Method
• Move Method
Heuristics and Code Smells
• Visual Studio Metrics
Code Smell: Regions
More on Regions: http://ardalis.com/regional-differences
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
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
Common Refactorings
• Extract Interface / Apply Strategy Pattern
• Parameterize Method
• Form Template Method
OCP Fail
OCP OK
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;
}
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;
}
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.
Common Refactorings
• Collapse Hierarchy
• Pull Up / Push Down Field
• Pull Up / Push Down Method
Liskov Substitution Fail
foreach(var employee in employees)
{
if(employee is Manager)
{
Helpers.PrintManager(employee as Manager);
break;
}
Helpers.PrintEmployee(employee);
}
Liskov Substitution OK
foreach(var employee in employees)
{
employee.Print();
// or
Helpers.PrintEmployee(employee);
}
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
Common Refactorings
• Extract Interface
Keep Interfaces Small and
Focused
Membership Provider
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);
}
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);
}
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#
Dependency Inversion Principle
• Depend on Abstractions
– Interfaces, not concrete types
• Inject Dependencies into Classes
• Structure Solution so Dependencies Flow
Toward Core
– Onion Architecture (a.k.a. Ports and Adapters)
Application Layers
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
Data Access : Helper
Classes
 Calls to data made through a
Compile Time
Runtime
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
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!
Database
DIP Architecture (aka Ports and
Adapters)
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
Common Refactorings
•
•
•
•
Extract Class
Extract Interface / Apply Strategy Pattern
Extract Method
Introduce Service Locator / Container
DIP Fail
Some Improvement (Façade)
DIP OK (Strategy)
DIP OK (Strategy)
Self-Improvement and Quality
• How fast can you produce:
– Code you believe to be of high quality
– Code that maybe gets the job done, but you
believe to be of low quality
• Which one can you produce more quickly?
• Why?
• How can we develop our skills and our tools
so that building quality is natural and easier
than not doing so?
User Stories Completed
16
14
12
10
8
6
4
2
0
Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7 Week 8 Week 9
High Quality
Low Quality
Column1
User Stories Completed
20
18
16
14
12
10
8
6
4
2
0
Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7 Week 8 Week 9
High Quality
Low Quality
Column1
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
• Train and Practice to Write Better Code
Faster
References
http://bit.ly/SFkpmq
 Refactoring Catalog
 http://www.refactoring.com/catalog/index.html
 Onion Architecture
 http://jeffreypalermo.com/blog/the-onion-architecture-part-1/
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
Thank you!
@ardalis
ardalis.com
http://facebook.com/stevenandrewsmith