Title: Refactoring
1Refactoring
2Definition
The process of changing a software system in such
a way that it does not alter the external
behavior of the code, yet improves its internal
structure. It is a disciplined way to clean up
code that minimizes the chances of introducing
bugs. Improving the design after its been
written.
3Video Store Example
4Video Store Example
5Impressions of this code?
Not really OO. Poor organization. Statement
routine supiciously long. What if we had to
change, I.e. put statement in HTML? What if
charging rules change? What if we add new rental
category?
6First step in refactoring
PREPARE TESTS Always refactor in small steps and
test after each refactoring.
7Refactoring 1 Extract method.
private double amountFor(Rental each)
double thisAmount 0 switch
(each.getMovie().getPriceCode()) case
Movie.REGULAR thisAmount 2
if (each.getDaysRented() gt 2)
thisAmount (each.getDaysRented() - 2) 1.5
break case Movie.NEW_RELEASE
thisAmount each.getDaysRented() 3
break case Movie.CHILDRENS
thisAmount 1.5 if (each.getDaysRented(
) gt 3) thisAmount (each.getDaysRented
() - 3) 1.5 break return
thisAmount
switch (each.getMovie().getPriceCode())
case Movie.REGULAR thisAmount 2
if (each.getDaysRented() gt 2)
thisAmount (each.getDaysRented() - 2) 1.5
break case Movie.NEW_RELEASE
thisAmount each.getDaysRented() 3
break case Movie.CHILDRENS
thisAmount 1.5 if
(each.getDaysRented() gt 3) thisAmount
(each.getDaysRented() - 3) 1.5
break
thisAmount amountFor(each)
8Refactoring 2 Renaming Variables
private double amountFor(Rental aRental)
double result 0 switch (aRental.getMovie().
getPriceCode()) case Movie.REGULAR
result 2 if (aRental.getDaysRented() gt
2) result (aRental.getDaysRented() -
2) 1.5 break case
Movie.NEW_RELEASE result
aRental.getDaysRented() 3 break
case Movie.CHILDRENS result 1.5
if (aRental.getDaysRented() gt 3) result
(aRental.getDaysRented() - 3) 1.5
break return result
9Refactoring 3 Move Method
//add to rental class double getCharge()
double result 0 switch
(getMovie().getPriceCode()) case
Movie.REGULAR result 2 if
(getDaysRented() gt 2) result
(getDaysRented() - 2) 1.5 break
case Movie.NEW_RELEASE result
getDaysRented() 3 break case
Movie.CHILDRENS result 1.5
if (getDaysRented() gt 3) result
(getDaysRented() - 3) 1.5 break
return result
//and adjust customer class private double
amountFor(Rental aRental) return
aRental.getCharge()
10Refactoring 3a. Cleanup Move method
Rental each (Rental) rentals.nextElement()
thisAmount each.getCharge()
And we get rid of amountFor method.
11Refactoring 4 Replace temp with query
while (rentals.hasMoreElements()) double
thisAmount 0 Rental each (Rental)
rentals.nextElement() thisAmount
each.getCharge() // Add frequent renter
points frequentRenterPoints
// Add bonus for a two-day, new-release rental
if ((each.getMovie().getPriceCode()
Movie.NEW_RELEASE) each.getDaysRented()
gt 1) frequentRenterPoints //
Show figures for this rental result "\t"
each.getMovie().getTitle() "\t"
Sting.valueOf(each.getCharge()) "\n"
totalAmount each.getCharge()
thisAmount each.getCharge() // Add
frequent renter points
frequentRenterPoints // Add bonus for
a two-day, new-release rental if
((each.getMovie().getPriceCode()
Movie.NEW_RELEASE) each.getDaysRented()
gt 1) frequentRenterPoints //
Show figures for this rental result "\t"
each.getMovie().getTitle() "\t"
Sting.valueOf(thisAmount) "\n"
totalAmount thisAmount
12Refactoring 5 Extract Method
// Add frequent renter points
frequentRenterPoints // Add bonus for a
two-day, new-release rental if
((each.getMovie().getPriceCode()
Movie.NEW_RELEASE) each.getDaysRented()
gt 1) frequentRenterPoints
frequenRenterPoints each.getFrequentRenterPoint
s()
//add to rental class int getFrequentRenterPoints
() if ((getMovie().getPriceCode()
Movie.NEW_RELEASE) getDaysRented() gt
1) return 2 else return 1
13Now get rid of hard-coded types
- Replace type code with State/Strategy
- Self-Encapsulate Field
- Move Method
- Replace conditional with Polymorphism
14When to refactor
- Rule of Three First time just do it. Second
time, wince at duplication, Third time, refactor. - When you add functionality.
- When you need to fix a bug.
- As you do code review. (Active Reviews)
15Bad Smells in code
- Duplicated Code (Extract Method)
- Long Method (Extract Method)
- Large Class (Extract Class)
- Long Parameter List (Remove Parameter)
- Divergent Change (Extract Class)
- Shotgun Surgery (Move Method, Move Field)
- Feature Envy (Move/Extract Method)
16More Bad Smells
- Data Clumps (Introduce Parameter Object)
- Primitive Obsession
- Switch Statements
- Parallel Inheritance Hierarchies
- Lazy Class
- Speculative Generality
17Even More Bad Smells
- Temporary Field
- Message Chains
- Middle Man
- Inappropriate Intimacy
- Alternative Classes with different interfaces
- Incomplete library class
- Data class
- Refused Bequest
- Comments
18Tool Support
- Smalltalk Refactoring Browser
- IntelliJ (Commercial)
- Eclipse
- Others on web site