Refactoring - PowerPoint PPT Presentation

1 / 66
About This Presentation
Title:

Refactoring

Description:

Compile and test after changing each reference. Declare the field as private. Compile and test. Refactoring works in tiny steps. 9. SQI, Griffith University ... – PowerPoint PPT presentation

Number of Views:42
Avg rating:3.0/5.0
Slides: 67
Provided by: ExternalR4
Category:

less

Transcript and Presenter's Notes

Title: Refactoring


1
Refactoring
  • Dr. Dan Powell

SQI, Griffith University
2
What is Refactoring
  • When you recognize that the design, tests, or
    code proper have structural flaws, you need to
    refactor.
  • Refactoring is the process of changing a software
    system such that the external behavior of the
    system does not change
  • functional requirements are maintained but the
    internal structure of the system is improved
  • that is, you do not modify the feature set at all

3
Why?
  • To improve the quality of the codebase
  • Makes software easier to understand, therefore
    maintain, extend, verify,...
  • It is difficult to get a design right the first
    time (iterative and incremental)
  • Systems evolve maintenance is highest cost in
    SDLC.

4
What refactoring isnt
  • Refactoring is not an opportunity to add features
  • Refactoring is not performance optimisation which
    often leads to code that is harder to understand.

5
When?
  • Rule of three
  • If you do the same thing the same three times in
    an implementation its time to refactor to remove
    duplication.
  • Refactor when you add new functionality
  • before to make it easier to incorporate new
    function
  • after to clean up
  • If the code is not structured conveniently to add
    a feature, first refactor the program to make it
    easy to add the feature, then add the feature
  • Refactor when you fix a defect
  • Refactor as part of code review process (edit)

6
When not to?
  • When it is easier to start again
  • Refactoring often requires changes to the
    interface, so refactoring is not a good idea
    when
  • you do not own all of the calling code
  • you have published the interface for other
    clients use
  • Many refactorings have an adverse effect on
    efficiency (time/resource) if efficiency is a
    higher architectural priority than
    maintainability, dont apply refactorings if they
    will effect efficiency.
  • This is rarely the case these days (exceptions
    include things like embedded and/or real-time
    systems).

7
Safe Refactoring
  • Use refactoring patterns
  • Fowler et. al., Refactoring Improving the
    Design of Existing Code
  • Test constantly
  • Ensure you have an adequate set of tests before
    refactoring
  • Make sure you are 100 compliant with tests
    before refactoring
  • Refactor
  • Make sure you are 100 compliant with tests after
    refactoring
  • If program fails a test, you know about it
    straight away

8
An example Refactoring
  • Encapsulate Field
  • To make clients of an object use methods to
    access a field rather than the field directly
  • Encapsulate Field (cookbook)
  • Create accessor and mutator methods for the field
  • Locate all references to the field and replace
    all calls to field with calls to accessor and all
    changes to the field with calls to the mutator.
  • Compile and test after changing each reference
  • Declare the field as private
  • Compile and test
  • Refactoring works in tiny steps

9
An example Refactoring
  • Original Code
  • public class Person public String name
  • Original Client
  • ...
  • Person person
  • person.name Joe Bloggs
  • assertEquals(Joe Bloggs, person.name)
  • ...

10
An example Refactoring
  • Step 1 Create Accessors and Mutators
  • public class Person
  • public String name
  • public String getName() return name
  • public void setName(String n) name n
  • Client
  • ...
  • Person person
  • person.name Joe Bloggs
  • assertEquals(Joe Bloggs, person.name)
  • ...

11
An example Refactoring
  • Step 2 Replace direct references with accessors
    and mutators
  • public class Person
  • public String name
  • public String getName() return name
  • public void setName(String n) name n
  • New Client
  • ...
  • Person person
  • person.setName(Joe Bloggs)
  • assertEquals(Joe Bloggs, person.name)
  • ...

Compile and Test
12
An example Refactoring
  • Step 2 Replace direct references with accessors
    and mutators
  • public class Person
  • public String name
  • public String getName() return name
  • public void setName(String n) name n
  • New Client
  • ...
  • Person person
  • person.setName(Joe Bloggs)
  • assertEquals(Joe Bloggs, person.getName())
  • ...

Compile and Test
13
An example Refactoring
  • Step 3 Make Field private
  • public class Person
  • private String name
  • public String getName() return name
  • public void setName(String n) name n
  • New Client
  • ...
  • Person person
  • person.setName(Joe Bloggs)
  • assertEquals(Joe Bloggs, person.getName())
  • ...

Compile and Test
14
How? Look for Bad Smells - Fowler
  • Duplicated Code
  • Long methods
  • Large Classes
  • Long parameter lists
  • Divergent Change
  • Shotgun Surgery
  • Feature Envy
  • Data Clumps
  • Primitive Obsession
  • Switch statements
  • Parallel Inheritance Hierarchies
  • Lazy Class
  • Speculative Generality
  • Temporary Field
  • Message Chain
  • Middle Man
  • Inappropriate Intimacy
  • Alternate classes different names
  • Incomplete Library Class
  • Data Class
  • Refused Bequest
  • Comments

15
Some Common Refactorings
  • Extract Method
  • Replace Temp with Query
  • Move Method

16
Extract Method
  • When?
  • Duplicate Code
  • extract out common code into separate method
  • Long Method
  • extract a number of smaller, more cohesive
    methods
  • Comments
  • extract individually commented blocks to a
    separate method

17
Extract Method - Example
  • public double correlation(double x, double
    y, int len)
  • // calculate sum of xy products
  • int i 0 double sumProd 0
  • while (i lt len)
  • sumProd sumProd xiyi
  • ...
  • // calculate sum of squares x
  • i 0 double sumSquaresX 0
  • while (i lt len)
  • sumSquaresX sumSquaresX xixi
  • // calculate sum of squares y
  • i 0 double sumSquaresY 0
  • while (i lt len)
  • sumSquaresY sumSquaresY yiyi
  • ...

18
Extract Methods
  • Smells, Symtoms and Refactorings
  • Comments in code commenting blocks
  • extract method extract separate methods for
    each block
  • Duplicate Code
  • extract method extract common code to a single
    method

19
Original - Comments
  • // calculate sum of xy products
  • int i 0 double sumProd 0
  • while (i lt len)
  • sumProd sumProd xiyi

20
Refactoring - Comments
  • public double sumProd( double x,double y,
    int len )
  • int i 0 double sumProd 0
  • while (i lt len)
  • sumProd sumProdxiyi
  • return sumProd
  • double sumProd sumProd(x,y,len)

21
Original Duplicate Code
  • // calculate sum of squares x
  • i 0 double sumSquaresX 0
  • while (i lt len)
  • sumSquaresXsumSquaresXxixi
  • // calculate sum of squares y
  • i 0 double sumSquaresY 0
  • while (i lt len)
  • sumSquaresYsumSquaresYyiyi

22
Refactoring Duplicate Code
  • public double sumSquares(double a, int len )
  • int i 0 double sumSquares 0
  • while (i lt len)
  • sumSquaressumSquaresaiai
  • return sumSquares
  • double sumSquaresXsumSquares(x,len)
  • double sumSquaresYsumSquares(y,len)

23
Refactoring
  • public double correlation(double x, double
    y, int len)
  • ...
  • double sumProd sumProd(x,y,len)
  • double sumSquaresX sumSquares(x,len)
  • double sumSquaresY sumSquares(y,len)
  • ...

24
Long Method
  • Symptoms
  • Large number of lines in a method (some people
    say over 5 to 10 is too many)
  • Causes
  • Doing more than one cohesive thing in a method
  • Refactoring
  • Extract Method to break up method to smaller
    methods

25
Long Method Example
  • public static void report(Writer out, List
    machines, Robot robot)
  • throws IOException
  • out.write("FACTORY REPORT\n")
  • Iterator line machines.iterator()
  • while (line.hasNext())
  • Machine machine (Machine) line.next()
  • out.write("Machine " machine.name())
  • if (machine.bin() ! null)
  • out.write(" bin" machine.bin())
  • out.write("\n")
  • out.write("\n")
  • out.write("Robot")
  • if (robot.location() ! null)
  • out.write(" location"
    robot.location().name())
  • if (robot.bin() ! null)
  • out.write(" bin" robot.bin())
  • out.write("\n")
  • out.write("\n")

26
Long Method Example
  • public static void report(Writer out, List
    machines, Robot robot)
  • throws IOException
  • out.write("FACTORY REPORT\n")
  • Iterator line machines.iterator()
  • while (line.hasNext())
  • Machine machine (Machine) line.next()
  • out.write("Machine " machine.name())
  • if (machine.bin() ! null)
  • out.write(" bin" machine.bin())
  • out.write("\n")
  • out.write("\n")
  • out.write("Robot")
  • if (robot.location() ! null)
  • out.write(" location"
    robot.location().name())
  • if (robot.bin() ! null)
  • out.write(" bin" robot.bin())
  • out.write("\n")
  • out.write("\n")

27
Long Method Example
  • public static void report(Writer out, List
    machines, Robot robot) throws IOException
  • reportHeader(out)
  • reportMachines(out, machines)
  • reportRobot(out, robot)
  • reportFooter(out)

28
Long Parameter List
  • Symptoms
  • A method has many parameters (some say more than
    one or two)
  • Causes
  • Attempt to minimise coupling
  • Genralised algorithm
  • Refactoring
  • If parameter can be obtained from another object
    already known to this one, Replace Parameter with
    Method.
  • If the parameters come from a single object, try
    Preserve Whole Object
  • If the data is not from one logical object, maybe
    group them with Introduced Parameter

29
Long Parameter List - Example
  • public void paintComponent(Graphics gr, Component
    renderer, Container parent, int x, int y, int
    width, int height, Boolean shouldValidate)
  • Introduce Parameter Object
  • public void paintComponent(Graphics gr, Component
    renderer, Container parent, Rectangle rect,
    Boolean shouldValidate)

30
Replace Temp with Query
  • Symptoms
  • Using temporary variable to hold result of
    calculation (expression)
  • Refactoring
  • Extract expression to method and replace all
    references to temp with call to method.

31
Replace Temp with Query e.g.
  • public double correlation(double x, double
    y, int len)
  • ...
  • double sumProd sumProd(x,y,len)
  • double sumSquaresX sumSquares(x,len)
  • double sumSquaresY sumSquares(y,len)
  • ...
  • return (lensumProd sumXsumY) /
  • (squareRoot( (lensumSquareX square(sumX))
  • (lensumSquareY square(sumY) ))

32
Replace Temp with Query - Refactoring
public double correlation(double x, double
y, int len) return (lensumProd(x,y,len)
sum(x,len)sum(y,len)) / (squareRoot(
(lensumSquare(x,len)- square(sum(x,len)))
(lensumSquare(y,len)- square(sum(y,len)))
))
33
Move Method
  • Symptoms
  • A method is using more features (attributes and
    operations) of another class than the class on
    which it is defined
  • Causes
  • Often caused as a result of other refactoring
  • Refactoring
  • Create a new method with a similar body in the
    class it uses most.
  • Either turn the old method into a simple
    delegation, or remove it altogether

34
Move Method Example
  • public class Report
  • public static void report(Writer out, List
    machines, Robot robot)
  • throws IOException
  • reportHeader(out)
  • reportMachines(out, machines)
  • reportRobot(out, robot)
  • reportFooter(out)
  • ...
  • private void reportRobot(Writer out, Robot
    robot)
  • out.write("Robot")
  • if (robot.location() ! null)
  • out.write(" location"
    robot.location().name())
  • if (robot.bin() ! null)
  • out.write(" bin" robot.bin())
  • out.write("\n")

35
Move Method Example
  • Move method to Robot Class
  • public class Robot
  • ...
  • public void reportRobot(Writer out)
  • out.write("Robot")
  • if (location() ! null)
  • out.write(" location"
  • location().name())
  • if (bin() ! null)
  • out.write(" bin" bin())
  • out.write("\n")
  • ...

36
Move Method Example
  • Change call in client
  • public class Report
  • public static void report(Writer out, List
    machines, Robot robot)throws IOException
  • reportHeader(out)
  • reportMachines(out, machines)
  • robot.reportRobot(out)
  • reportFooter(out)
  • ...
  • private void reportRobot(Writer out, Robot
    robot)
  • ...

37
Move Method Example
  • Remove method from client
  • public class Report
  • public static void report(Writer out, List
    machines, Robot robot) throws IOException
  • reportHeader(out)
  • reportMachines(out, machines)
  • robot.reportRobot(out)
  • reportFooter(out)

38
Replace Conditional withPolymorphism
  • Symptoms
  • You have a conditional that chooses different
    behavior depending on the type of an object
  • Refactoring
  • Move each leg of the conditional to an
    overriding method in a subclass.
  • Make the original method abstract

39
Refactoring
  • Get rid of the switch statement
  • class Movie double getCharge( int
    daysRented ) double result 0
    switch (getPriceCode()) case
    Movie.REGULAR result 2
    if (daysRented gt 2)
    result (daysRented - 2) 1.5
    break case Movie.NEW_RELEASE
    result daysRented 3
    break case Movie.CHILDRENS
    result 1.5 if
    (daysRented gt 3) result
    (daysRented - 3) 1.5 break
    return result

40
Refactoring
  • ?

41
Refactoring
  • Flaw
  • A movie may change its classification during its
    lifetime.
  • An object cannot change its class during its
    lifetime.

42
Refactoring
  • Solution
  • Use State design pattern.

43
(No Transcript)
44
Refactoring
  • Replace price (type) code
  • Apply Replace Type Code with State.
  • Compile and test after each step.

45
Refactoring
  • public class Movie private int
    _priceCode public Movie( String title, int
    priceCode ) _title title
    _priceCode priceCode public int
    getPriceCode() return _priceCode
    public void setPriceCode( int arg )
    _priceCode arg

46
Refactoring
  • public class Movie private int
    _priceCode public Movie( String title, int
    priceCode ) _title title
    setPriceCode(priceCode) public int
    getPriceCode() return _priceCode
    public void setPriceCode( int arg )
    _priceCode arg

47
Refactoring
  • Add new state classesabstract class Price
    public abstract int getPriceCode()class
    RegularPrice extends Price public int
    getPriceCode() return Movie.REGULAR
    class NewReleasePrice extends Price
    public int getPriceCode() return
    Movie.NEW_RELEASE class ChildrensPrice
    extends Price public int getPriceCode()
    return Movie.CHILDRENS

48
Refactoring
  • Replace price type codes with instances of price
    state classes

49
Refactoring
  • public class Movie private int
    _priceCode public int getPriceCode()
    return _priceCode public
    void setPriceCode( int arg ) _priceCode
    arg

50
  • public class Movie private Price
    _price public int getPriceCode()
    return _price.getPriceCode()
    public void setPriceCode( int arg )
    switch (arg) case REGULAR
    _price new RegularPrice()
    break case NEW_RELEASE
    _price new NewReleasePrice()
    break case CHILDRENS
    _price new ChildrensPrice()
    break default
    throw new IllegalArgumentException( Incorrect
    price code )

51
  • class Movie double getCharge( int
    daysRented ) double result 0
    switch (getPriceCode()) case
    Movie.REGULAR result 2
    if (daysRented gt 2)
    result (daysRented - 2) 1.5
    break case Movie.NEW_RELEASE
    result daysRented 3
    break case Movie.CHILDRENS
    result 1.5 if
    (daysRented gt 3) result
    (daysRented - 3) 1.5 break
    return result

52
Refactoring
  • Move getCharge() to Price class
  • Apply Move Method.

53
  • class Price double getCharge( int
    daysRented ) double result 0
    switch (getPriceCode()) case
    Movie.REGULAR result 2
    if (daysRented gt 2)
    result (daysRented - 2) 1.5
    break case Movie.NEW_RELEASE
    result daysRented 3
    break case Movie.CHILDRENS
    result 1.5 if
    (daysRented gt 3) result
    (daysRented - 3) 1.5 break
    return result

54
  • class Movie double getCharge( int
    daysRented ) return _price.getCharge(
    daysRented )

55
  • class Price double getCharge( int
    daysRented ) double result 0
    switch (getPriceCode()) case
    Movie.REGULAR result 2
    if (daysRented gt 2)
    result (daysRented - 2) 1.5
    break case Movie.NEW_RELEASE
    result daysRented 3
    break case Movie.CHILDRENS
    result 1.5 if
    (daysRented gt 3) result
    (daysRented - 3) 1.5 break
    return result

56
Refactoring
  • Replace switch statement in getCharge()
  • For each case, add overriding method.
  • Define abstract method.
  • Apply Replace Conditional with Polymorphism.

57
  • class RegularPrice double getCharge( int
    daysRented ) double result 2
    if (daysRented gt 2) result
    (daysRented - 2) 1.5 return result
    class NewReleasePrice double
    getCharge( int daysRented ) return
    daysRented 3 class ChildrensPrice
    double getCharge( int daysRented )
    double result 1.5 if (daysRented gt 3)
    result (daysRented - 3) 1.5

58
  • class Price abstract double
    getCharge( int daysRented )

59
Refactoring
  • Replace if statement in getFrequentRenterPoints()
  • Apply Replace Conditional with Polymorphism.

60
Refactoring
  • class Price int getFrequentRenterPoin
    ts( int daysRented ) if
    ((getPriceCode() Movie.NEW_RELEASE)
    daysRented gt 1) return 2
    else return 1

61
Refactoring
  • class Price int getFrequentRenterPoin
    ts( int daysRented ) return 1
    class NewReleasePrice int
    getFrequentRenterPoints( int daysRented )
    return (daysRented gt 1) ? 2 1

62
Refactoring
  • Result of state design pattern
  • easy to change price behavior
  • can add new price codes
  • rest of application does not know about this use
    of the state pattern

63
Refactoring
  • Benefits of second refactoring
  • easy to change movie classifications
  • easy to change rules for charging and frequent
    renter points

64
(No Transcript)
65
Refactoring
66
References
  • Refactoring
  • M. Fowler et al.
  • Addison-Wesley, 1999
  • Refactoring Workbook
  • W. Wake
  • Addison-Wesley, 2003
  • http//xp123.com/rwb/ - Sample chapter, exercises
    and sample code that needs refactoring
Write a Comment
User Comments (0)
About PowerShow.com