refactoring - a disciplined approach to rework for better design
TRANSCRIPT
Refactoring
- A disciplined approach to rework for better design.
Objectives
•What is refactoring?•History•Why should I refactor? •When should I refactor?•How to refactor?
Definition•Refactoring is a disciplined technique for
restructuring an existing body of code, altering its internal structure without changing its external behavior.
• It makes the software easier to understand and cheaper to modify.
Continued..•Example: compute gravitational potential energy
▫PEgrav = mass * g * height
double potentialEnergy(double mass, double height) { return mass * height * 9.81; }
static final double GRAVITATIONAL_CONSTANT = 9.81;
double potentialEnergy(double mass, double height) { return mass * height * GRAVITATIONAL_CONSTANT; }
Magic number
Properties of Refactoring
•One step at a time
•Preserve correctness
•Frequent testing
Where did refactoring come from ?
For a long time it was a piece of programmer lore, done withvarying degrees of discipline by experienced developers, butnot passed on in a coherent way.
• Kent Beck and Ward Cunningham were two of the first people to recognize the importance of refactoring▫ worked with Smalltalk from the 80's onward.
• Ralph Johnson's work with refactoring and frameworks has also been an important contribution.
• Martin Fowler’s book Refactoring: Improving the Design of Existing Code is the classic reference.
Why refactor?• Improves the design of software.
▫Without refactoring, the design of the program will decay
•Makes software easier to understand.▫A good design is easy to understand
•Helps you find bugs.▫The clarification process helps find bugs
•Helps you program faster.▫Poor design slow you down
When to Refactor? •As you develop
▫Example: change a variable name to something more meaningful.
•Before adding functions.▫Sometimes the existing design does not allow you to easily
add the feature.•When you need to fix a bug
▫The bug exists because the code was not clear enough for you to see the bug in the first place.
•When you do a code review▫Code reviews help spread knowledge through the
development team.▫Works best with small review groups
Steps to refactoring
• Identifying bad smells of code▫a “bad smell” = a warning sign in the code▫e.g., time consuming code
•Designing solid tests ▫for the section of code under analysis.
•Refactoring the code ▫based on the type of the smell
•Applying tests.
Bad Smells in Code•Duplicated Code•Long Method•Large Class•Long Parameter List•Divergent Change•Shotgun Surgery•Feature Envy•Data Clumps•Primitive Obsession•Switch Statements
• Parallel Interface Hierarchies• Lazy Class• Speculative Generality• Temporary Field• Message Chains • Middle Man• Inappropriate Intimacy• Incomplete Library Class• Data Class• Refused Bequest
Bad smells in code•Smells within classes
▫Duplicated code▫Long method▫Large class▫…
•Smells between classes▫Primitive obsession ▫ Inappropriate intimacy▫Middle man▫…
Duplicated Code – (1)
•“The #1 bad smell” ▫If you see the same code structure in more than one
place, you can be sure that your program will be better if you find a way to unify them.
▫What if duplicates changes
•Refactoring solutions▫Pull up a field▫Form a template method▫Substitute algorithm
Duplicated Code – (2)•Pull up a field
▫Two subclasses have the same field.▫Move the field to the superclass.
Salesman Engineer
Employee
name name
Duplicated Code – (3)•Form a template method
▫You have two methods in subclasses that perform similar steps in the same order, yet the steps are different.
▫Get the steps into methods with the same signature, so that the original methods become the same. Then you can pull them up.
Duplicated Code – (4)•Form a template method
PersonalCustomer
CorporateCustomer
Customer
getBillableAmt() getBillableAmt()
double base=unit*ratedouble tax=base*Site.TAX_RATE;return base+tax
double base=unit*rate*0.5double tax=base*Site.TAX_RATE*0.2;return base+tax
getBaseAmt()getTaxAmt()
getBaseAmt()getTaxAmt()
return getBaseAmt()+getTaxAmt()
getBaseAmt()getTaxAmt()
Duplicated Code – (5)• Substitute algorithm
▫ Replace the body of the method with the new algorithm.
duplications
Long Method – (1)
•The longer the method the harder it is to see what it’s doing. ▫Poorly thought out abstractions and boundaries
•Refactoring solutions▫Extract method▫Replace temp with query▫ Introduce parameter object▫Preserve whole object
Long Method – (2)
•Extract method▫ break up into smaller
private methods within the class
• Example
private void m1(){Statement 1;..Statement 9;}
private void m2(){Statement 10;..Statement 19;}
private void m3(){Statement 20;..Statement 30;}
public void methodA(){
}
public void methodA(){
Statement 1;Statement 2;..Statement 30;} m1();
m2();
m3();
Long Method – (3)• Replace temp with query
▫You are using a temporary variable to hold the result of an expression.
▫Extract the expression into a method.
if (basePrice() > 1000) { return basePrice() * 0.95;} else { return basePrice() * 0.98; }
Temp variable
expression
double basePrice=basePrice();if (basePrice > 1000) { return basePrice * 0.95;} else { return basePrice * 0.98; }
Long Method – (4)• Introduce parameter object
▫A group of parameters that naturally go together.▫Replace them with an object.
amountInvoicedIn ( )amountReceivedIn ( )amountOverdueIn ( )
Customerstart: Dateend: Date
DateRangeDateRange
Start: Date, end: DateStart: Date, end: DateStart: Date, end: Date
DateRangeDateRange
Long Method – (5)•Preserve whole object
▫You are getting several values from an object and passing these values as parameters in a method call.
▫Send the whole object instead.
Large Class – (1)
•A class that is trying to do too much ▫Can usually be identified by looking at how many
instance variables it has. ▫When a class has too many instance variables,
duplicated code cannot be far behind. •Refactoring solution
▫Extract class▫Extract subclass
PhoneNumber
Large Class – (2)•Extract class
▫Have one class doing work that should be done by two.▫Need create a new class and move the relevant fields
and methods from the old class into the new class.
Customer
nameareaCodenumber
String: getPhoneNumber()
PhoneNumber: getPhoneNumber()
LaborItem
Large Class – (3)• Extract subclass
▫A class has features that are used only in some instances.
▫Create a subclass for that subset of features.
JobItem
getTotalPrice()getUnitPrice()getEmployee()
Do all the JobItem objects need have getEmployee
function?
getUnitPrice()
Primitive Obsession – (1)•Over use primitive to represent data
▫All properties of a class are primitive types int, String, boolean, double, etc.
▫Primitive difficult to represent data money (which combines quantity and currency) a date range object
• Refactorings▫Replace data value with object ▫Replace type code with class
Primitive Obsession – (2)•Replace data value with objects
▫You have a data item that needs additional data or behavior.
▫Turn the data item into an object.
Order
customer: String
Customer
id: Stringlast Name:: StringmiddleName: StringfirstName: Stringphone: PhoneNumber
Primitive Obsession – (3)•Replace type code with class
▫A class has a numeric type code that does not affect its behavior.
▫Replace the number with a new class.
Person
O: intA: intB:intAB:int
BloodType
O: BloodTypeA: BloodTypeB: BloodTypeAB: BloodType
bloodType:int
public class Person{ …… int bloodType =BloodType.O; …….}
public class BloodType{ public static final int O 1; public static final int A 2; public static final int B 3; public static final int AB 4;}
Inappropriate Intimacy – (1)•Two classes are overly entertwined
▫Sharing of secrets between classes▫Leads to data coupling
•Refactorings▫Hide delegate▫Replace inheritance with delegation
What is that?
Inappropriate Intimacy – (2)•Hide delegate
▫A client is calling a delegate class of an object.▫Create methods on the server to hide the delegate.
Client
Server
Delegate
taskA() taskA()
public void method(){ delegate.taskA();}
Inappropriate Intimacy – (3)
ClientClass
Employee
Department
getDepartment() getManager()
public class Department{ private Employee manager; …… public Department (Employee manager){ this.manager=manager; } public string getManager(){ return manager; } …..}
manager=john.
Object need to know less about other parts of the
system
public getManager(){ return department.getManager();}
getManager()
getDepartment().
getManager();
Inappropriate Intimacy – (3)• Replace inheritance with delegation
▫ A subclass uses only part of a superclasses interface or does not want to inherit data.
▫ Create a field for the superclass, adjust methods to delegate to the superclass, and remove the subclassing.
Middle ManInline Method• A method's body is just as clear as its name • Refactoring solution
▫ Put the method's body into the body of its callers and remove the method.
int getRating() { return (moreThanFiveLateDeliveries()) ? 2 :
1; }
boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5;
}
int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1;
}
Why might you still not refactor your programs?•You might not understand how to refactor.
• If the benefits are long-term, why exert the effort now? In the long term, you might not be with the project to reap the benefits!
•Refactoring code is an overhead activity; you're paid to write new features.
•Refactoring might break the existing program.
Summary•Refactoring is a disciplined approach to rework
for better design.•Refactor when code smells.•Take advantage of IDE (Eclipse/IntelliJ/ Java
Studio).•Check online resources for updated refactoring.•Know refactoring before your interview.
References
•http://wiki.java.net/bin/view/People/SmellsToRefactorings
•https://netfiles.uiuc.edu/dig/RefactoringInfo/
•http://www.refactoring.com/
Questions?