Upload
vmandrychenko
View
3.036
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
Refactoring - Improving the smell of your codeVlad Mandrychenko
October 2011
Agenda
• What is refactoring?• Why refactor?• When NOT to refactor?• When to refactor?• Code Smells• How to refactor?• Refactoring Tools
What is refactoring?
• Disciplined technique for restructuring existing code without changing its external behavior.
• Series of small (measured in minutes) behavior preserving code transformations.
Why refactor?
• To make code easier to work with in the future
• Speed up development
• Code is written once but is read many times
• Developers of all skill levels must be able to understand the code
Why refactor?
• To improve design o Improve reusability and remove duplicationo Allow for easier extensions and align code with
functionality and usageo Reduce complexity
• Improving code quality and rigidity, reduce bugs
• Simplify testing
Why refactor?
• Dramatically reduce development cost and headaches
When NOT to refactor?
• When it has no immediate business valueo Refactoring should be done as part of fixing a defect
or adding new feature
• Code does not work
• Inadequate test coverage
• Breaking used interfaces
• Requires expensive data migrations
• Tight deadline
When to refactor?
• During defect fix or addition of a new feature
• When code is hard to read and understand
• When code requires complex unit
tests • When upcoming changes are not
easily supported by existing code • Existing code requires a change
every time new feature is added • As result of code reviews
How to refactor
• Know your end goal
• Add missing unit tests
• Ensure unit tests pass before you start and in between each small refactoring
• Small, incremental, purposeful commits
• Stop when you are unsure
• Backtrack
• Pairing/Code Reviews
Refactoring and Design Patterns
• Go hand in hand
• Using patterns to improve existing design is better then using patterns in the new design
o When designing new system, devs: Don't know all the requirements
Don't have a full working application
Guessing as to which patterns are actually applicable
Tend to over-engineer
Code smell?
• Code smell is a possible symptom of the deeper problem
Duplicate codeif (isSpecialDeal()) { total = price * 0.95; send(); } else { total = price * 0.98; send(); }
Long and complicated methods/classespublic class PromotionFilterServiceImpl{ public LoyaltyProgramVO filter(... ...){ //1 method, 2 nested loops, 13 if statements, 80 lines of code = 1000+ lines test class }}
Code smell?
Too many method params public void calculate(int from, int to, int x, int y, int ...){}
Ungrouped related fieldsclass DayCalculator { private Date to; private Date from; private boolean skipSaturday; private boolean skipSunday; ..... }
God classesclass ManagerServiceHelperImpl { public BigInt calculatePrice() { //calculate stuff } public void handleResponse(){ //handle stuff }
public Report manageReportPrinter(){ // manage stuff }
public boolean isCanDoEverything() { return true; }}
Code smell?
Unused/temporary object fieldspublic class SessionVO { private PartnerFeatureVO partnerFeatureVO = null; private ReserveCertificateVO reserveCertificateVO; // only used for claim private boolean giftOrTransfer; ...... ...... }
Complicated VOs and Data Classespublic class SessionVO { // contains 20 different nested mutable objects // contains over 100 variables // unknown lifecycle}
Code smells (cont'd)
Numerous switch/if/else statements public double calculateArea(Object shape) { double area = 0; if (shape instanceof Square) { Square square = (Square) shape; area = square.getA() * square.getA(); } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; area = rectangle.getA() * rectangle.getB(); } } else if (shape instanceof Circle) { Circle circle = (Circle) shape; area = Math.PI * cirle.getR() * cirle.getR(); } return area; }
Deep method chains getHelper(){ getHandlerHelper(){ handleResponse(){ processReport();{ } } } }
Code smells (cont'd)
Commentsclass DistanceCalculator(){ // FIXME: rename this method public int process(Coordinates coords){ //this method calculates the distance between 2 coordinates ..... . ..... }}
Cascading change• Small change in 1 place cascades into multiple
changes in other parts of the code
Refactoring Tools
• IDE
How to refactor: catalog of techniques
http://refactoring.com/catalog/index.html
How to refactor: some techniques
Rename Method
class DistanceCalculator(){ // FIXME: rename this method public int process(Coordinates coords){ //this method calculates the distance between 2 coordinates ..... . ..... }}
class DistanceCalculator(){ public int calculateDistance(Coordinates coords){ ..... . ..... }}
How to refactor: some techniques
Extract Interface
class Employee(){ double getRate(){ ... } boolean hasSpecialSkill(){ ... } getName (){ ... } getDepartment(){ ... }
}
interface Billable{ double getRate(); boolean hasSpecialSkill();}
class Employee implements Billable(){}class Contractor implements Billable(){}
How to refactor: some techniques
Introduce Parameter Object
public void calculate(int from, int to, int x, int y){ ... } public void calculate(Range range, Location location){ ... }
How to refactor: some techniques
Replace Conditional with Polymorphismpublic class Client { public double calculateArea(Object shape) { double area = 0; if (shape instanceof Square) { Square square = (Square) shape; area = square.getA() * square.getA(); } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; area = rectangle.getA() * rectangle.getB(); } } else if (shape instanceof Circle) { Circle circle = (Circle) shape; area = Math.PI * cirle.getR() * cirle.getR(); } return area; }}
public class Square implements Shape { private double a; ... public double getArea() { return a * a; }}public class Rectangle implements Shape { private double a; private double b; ... public double getArea() { return a * b; }}public class Client { private Shape shape; ... public double calculateArea() { return shape.getArea(); }}
How to refactor: some techniques
Replace Type Code with State/Strategy
How to refactor: some techniques
Replace Inheritance with Delegation
Reference Material
Books:• M Fowler -
Refactoring: Improving the Design of Existing Code • Gang Of Four - Design Patterns• Joshua Karievsky - Refactoring to Patterns
Websites:• refactoring.com• https://mwiki.points.com/wiki/SoftwareEngineering