Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Studying the Effect of Refactorings: a Complexity Metrics Perspective

qsoetens
March 17, 2012

Studying the Effect of Refactorings: a Complexity Metrics Perspective

Refactoring is widely recognized as a way to improve the internal structure of a software system in order to ensure its long-term maintainability. Consequently, software projects which adopt refactoring practices should see reductions in the complexity of their code base. We evaluated this assumption on an open source system ---namely PMD, a Java source code analyzer--- and discovered that periods of refactorings did not affect the cyclomatic complexity. This paper investigates this counterintuitive phenomenon through a detailed analysis of the actual source code manipulations applied on the system under study.

qsoetens

March 17, 2012
Tweet

More Decks by qsoetens

Other Decks in Research

Transcript

  1. Ansymo Antwerp Systems and Software Modelling Quinten David Soetens Serge

    Demeyer Studying the Effect of Refactorings: a Complexity Metrics Perspective
  2. [Lehman & Belady: Program Evolution: processes of software change (1985)]

    Lehman’s Laws I. Continuing Change: “A system must be continually adapted or it becomes progressively less satisfactory.” 2
  3. [Lehman & Belady: Program Evolution: processes of software change (1985)]

    Lehman’s Laws I. Continuing Change: “A system must be continually adapted or it becomes progressively less satisfactory.” II. Increasing Complexity: “As a system evolves its complexity increases unless work is done to maintain or reduce it.” 2
  4. [Lehman & Belady: Program Evolution: processes of software change (1985)]

    Lehman’s Laws I. Continuing Change: “A system must be continually adapted or it becomes progressively less satisfactory.” II. Increasing Complexity: “As a system evolves its complexity increases unless work is done to maintain or reduce it.” Solution = REFACTORING 2
  5. Related work Studies on the effect refactoring has on: •Quality

    •Understandability •Changeability •Reusability •Maintainability •Coupling & Cohesion Mixed conclusions!! 4
  6. Related work Studies on the effect refactoring has on: •Quality

    •Understandability •Changeability •Reusability •Maintainability •Coupling & Cohesion Mixed conclusions!! 4 What about Complexity??
  7. McCabe Cyclomatic Complexity • Measure for amount of decision logic

    (control flow complexity) per method. • Count nr of branches (for, while, if, do, case, catch.... ) • Count nr of boolean operators ( && , || ) • Nr of independent paths through control flow graph 5
  8. McCabe Cyclomatic Complexity • Measure for amount of decision logic

    (control flow complexity) per method. • Count nr of branches (for, while, if, do, case, catch.... ) • Count nr of boolean operators ( && , || ) • Nr of independent paths through control flow graph 5 public Rule getRuleByName(String ruleName) { for (Iterator i = rules.iterator(); i.hasNext();) { Rule r = (Rule)i.next(); if (r.getName().equals(ruleName)) { return r; } } throw new RuntimeException(.....); }
  9. McCabe Cyclomatic Complexity • Measure for amount of decision logic

    (control flow complexity) per method. • Count nr of branches (for, while, if, do, case, catch.... ) • Count nr of boolean operators ( && , || ) • Nr of independent paths through control flow graph 5 public Rule getRuleByName(String ruleName) { for (Iterator i = rules.iterator(); i.hasNext();) { Rule r = (Rule)i.next(); if (r.getName().equals(ruleName)) { return r; } } throw new RuntimeException(.....); }
  10. McCabe Cyclomatic Complexity • Measure for amount of decision logic

    (control flow complexity) per method. • Count nr of branches (for, while, if, do, case, catch.... ) • Count nr of boolean operators ( && , || ) • Nr of independent paths through control flow graph 5 public Rule getRuleByName(String ruleName) { for (Iterator i = rules.iterator(); i.hasNext();) { Rule r = (Rule)i.next(); if (r.getName().equals(ruleName)) { return r; } } throw new RuntimeException(.....); } CC = 3
  11. Theoretical Approach 7 Refactoring Complexity Change Pull Up Method Extract

    Method Inline Method C 1 = C 0 + CC Method − CC Method N C 1 = C 0 + CC Method − (CC Method −1)N C 1 = C 0 − CC Method + (CC Method −1)N Theoretical
  12. Pull Up Method 8 0 1 2 3 4 5

    0 1 2 3 4 5 N CC Decrease Equalize Increase Theoretical C 1 = C 0 + CC Method − CC Method N CC Method − CC Method N < 0 CC Method − CC Method N = 0 CC Method − CC Method N > 0
  13. 9 0 1 2 3 4 5 0 1 2

    3 4 5 N CC Theoretical Extract Method C 1 = C 0 + CC Method − (CC Method −1)N Decrease Equalize Increase CC Method − (CC Method −1)N < 0 CC Method − (CC Method −1)N = 0 CC Method − (CC Method −1)N > 0
  14. Extract Method (Equalize) 10 the rest of this section. We

    take ystem before the refactoring, C1 em after the refactoring and x as d upon which the refactoring is ng ctoring we move a method from ubsequently remove the duplicate bling classes. Suppose c is the d occurred (i.e., the number of hen we can write the complexity 0 + x − cx ed by adding a method in the ently removing the method from nted it (−cx). We can now see he same when only one (c = 1) m the subclasses (which is ba- ation). When more occurrences complexity will be lower. The e if no occurrences are removed ), but then we would simply add ass and this would no longer be ng oring creates a new method from n, occurrences of this code are wly created method. If we take es of the extracted piece of code d call, we can write the changed the for loop to a new method bar, as is shown on the right then the complexity of the method foo is reduced to two and the complexity of the new method is also two. So the total complexity remains four. public void foo(){ if(condition){ for(iteration){ ... } } for(iteration){ ... } } Listing 1. Before an Extract Method refactoring. public void foo(){ if(condition){ bar(); } bar(); } public void bar(){ for(iteration){ ... } } Listing 2. After an Extract Method refactoring. C. Inline Method Refactoring The Inline Method refactoring is the inverse of the Extract Theoretical
  15. Extract Method (Equalize) 10 the rest of this section. We

    take ystem before the refactoring, C1 em after the refactoring and x as d upon which the refactoring is ng ctoring we move a method from ubsequently remove the duplicate bling classes. Suppose c is the d occurred (i.e., the number of hen we can write the complexity 0 + x − cx ed by adding a method in the ently removing the method from nted it (−cx). We can now see he same when only one (c = 1) m the subclasses (which is ba- ation). When more occurrences complexity will be lower. The e if no occurrences are removed ), but then we would simply add ass and this would no longer be ng oring creates a new method from n, occurrences of this code are wly created method. If we take es of the extracted piece of code d call, we can write the changed the for loop to a new method bar, as is shown on the right then the complexity of the method foo is reduced to two and the complexity of the new method is also two. So the total complexity remains four. public void foo(){ if(condition){ for(iteration){ ... } } for(iteration){ ... } } Listing 1. Before an Extract Method refactoring. public void foo(){ if(condition){ bar(); } bar(); } public void bar(){ for(iteration){ ... } } Listing 2. After an Extract Method refactoring. C. Inline Method Refactoring The Inline Method refactoring is the inverse of the Extract Theoretical CC = 4
  16. Extract Method (Equalize) 10 the rest of this section. We

    take ystem before the refactoring, C1 em after the refactoring and x as d upon which the refactoring is ng ctoring we move a method from ubsequently remove the duplicate bling classes. Suppose c is the d occurred (i.e., the number of hen we can write the complexity 0 + x − cx ed by adding a method in the ently removing the method from nted it (−cx). We can now see he same when only one (c = 1) m the subclasses (which is ba- ation). When more occurrences complexity will be lower. The e if no occurrences are removed ), but then we would simply add ass and this would no longer be ng oring creates a new method from n, occurrences of this code are wly created method. If we take es of the extracted piece of code d call, we can write the changed the for loop to a new method bar, as is shown on the right then the complexity of the method foo is reduced to two and the complexity of the new method is also two. So the total complexity remains four. public void foo(){ if(condition){ for(iteration){ ... } } for(iteration){ ... } } Listing 1. Before an Extract Method refactoring. public void foo(){ if(condition){ bar(); } bar(); } public void bar(){ for(iteration){ ... } } Listing 2. After an Extract Method refactoring. C. Inline Method Refactoring The Inline Method refactoring is the inverse of the Extract Theoretical CC = 4 CC = 2 CC = 2
  17. Extract Method (Equalize) 10 the rest of this section. We

    take ystem before the refactoring, C1 em after the refactoring and x as d upon which the refactoring is ng ctoring we move a method from ubsequently remove the duplicate bling classes. Suppose c is the d occurred (i.e., the number of hen we can write the complexity 0 + x − cx ed by adding a method in the ently removing the method from nted it (−cx). We can now see he same when only one (c = 1) m the subclasses (which is ba- ation). When more occurrences complexity will be lower. The e if no occurrences are removed ), but then we would simply add ass and this would no longer be ng oring creates a new method from n, occurrences of this code are wly created method. If we take es of the extracted piece of code d call, we can write the changed the for loop to a new method bar, as is shown on the right then the complexity of the method foo is reduced to two and the complexity of the new method is also two. So the total complexity remains four. public void foo(){ if(condition){ for(iteration){ ... } } for(iteration){ ... } } Listing 1. Before an Extract Method refactoring. public void foo(){ if(condition){ bar(); } bar(); } public void bar(){ for(iteration){ ... } } Listing 2. After an Extract Method refactoring. C. Inline Method Refactoring The Inline Method refactoring is the inverse of the Extract Theoretical CC = 4 CC = 2 CC = 2 CC = 4
  18. 11 0 1 2 3 4 5 0 1 2

    3 4 5 N CC Theoretical Inline Method Decrease Equalize Increase CC Method − (CC Method −1)N < 0 CC Method − (CC Method −1)N = 0 CC Method − (CC Method −1)N > 0 C 1 = C 0 − CC Method + (CC Method −1)N
  19. Empirical Validation • • Analysis of revisions 17 to 810

    ≈ 776 revisions • = 2 months of development • Metric for each revision extracted using “Metrics” Eclipse Plugin 13 http://pmd.sourceforge.net/ Empirical
  20. Revisions with Refactorings 14 33 out of 776 (4.25%) of

    revisions mention “refactor” in comment Empirical
  21. Results 16 !""# $""# %""# &""# '""# (""# )""# *""#

    +"""# ++""# "# +""# !""# $""# %""# &""# '""# (""# )""# !"#$%&'()*+ ,&-(.("/+ !"#$%&'()*+0-"%12"/+ Results
  22. Results 16 !""# $""# %""# &""# '""# (""# )""# *""#

    +"""# ++""# "# +""# !""# $""# %""# &""# '""# (""# )""# !"#$%&'()*+ ,&-(.("/+ !"#$%&'()*+0-"%12"/+ Results
  23. Results 16 !""# $""# %""# &""# '""# (""# )""# *""#

    +"""# ++""# "# +""# !""# $""# %""# &""# '""# (""# )""# !"#$%&'()*+ ,&-(.("/+ !"#$%&'()*+0-"%12"/+ Results
  24. Results 17 !" #!" $!" %!" &!" '!" (!" )!"

    *!" +!" ,-./0" 1/234-50/6" !"#$"%&'()*' +,-./"01&2'+34%5"6' 7893:;</6"==" >?40/3@/6"==" A/40/3@/6"==" Results
  25. Results 17 Results !" #!!" $!!" %!!" &!!" '!!" (!!"

    )!!" *+,-." /-012+3.-4" 567189:-4";;" <=2.-1>-4";;" ?-2.-1>-4";;"
  26. Observations • Refactorings that cause Decreased CC • Removal of

    duplicated code (Extract Method or Pull Up Method) (6 cases) • Inline a Method, that is only called once (4 cases) • Removal of dead code (4 cases) 18 Results
  27. Observations • Refactorings that cause? Increased CC • Extract Method

    of single occurrence of a piece of code (1 case) • Addition of new functionality besides refactoring (“Floss Refactoring”) (7 cases) 19 Results
  28. Observations • Refactorings that cause Equalized CC • Introduce Explaining

    Variable (2 cases) • Rename Method (1 case) • Special Case of Extract Method (1 case) 20 Results
  29. Observations • Decreased CC not caused by Refactoring • Mostly

    due to removal of unnecessary methods / functionality. 21 Results
  30. Conclusions • Refactoring doesn’t always affect (Cyclomatic) Complexity • “Floss

    Refactoring” often applied by developers • Threats: • Other complexity metrics? • Use of commit messages to identify refactorings? • Only looked at “initial development” phase 23 Conclusion