Refactoring.pdf
COMP2511
Refactoring
Prepared by
Ashesh Mahidadia
Refactoring: Motivation
v Code refactoring is the process of restructuring existing computer code without
changing its external behavior.
v Originally Martin Fowler and Kent Beck defined refactoring as,
“A change made to the internal structure of software to make it easier to understand
and cheaper to modify without changing its observable behavior… It is a disciplined
way to clean up code that minimizes the chances of introducing bugs.”
v Advantages: improved code readability, reduced complexity; improved maintenance
and extensibility
v If done well, helps to identify hidden or dormant bugs or vulnerabilities, by simplifying
code logic.
v If done poorly, may change external behavior, and/or introduce new bugs!
v Refactoring is different to adding features and debugging.
COMP2511: Refactoring 2
Refactoring: Motivation
v Refactoring is usually motivated by noticing a code smell (possible bad design/coding
practices).
v Code Smell is a hint that something might be wrong, not a certainty.
v Identifying a Code Smell allows us to re-check the implementation details and consider
possible better alternatives.
v Automatic unit tests should be set up before refactoring to ensure routines still behave
as expected.
v Refactoring is an iterative cycle of making a small program transformation, testing it to
ensure correctness, and making another small transformation.
COMP2511: Refactoring 3
Software Maintenance
v Software Systems evolve over time to meet new requirements and features.
v Software maintenance involve:
• Fix bugs
• Improve performance
• Improve design
• Add features
v Majority of software maintenance is for the last three points!
v Harder to maintain code than write from scratch!
v Most of the development time is spent in maintenance!
v Good design, coding and planning can reduce maintenance pain and time!
v Avoid code smells to reduce maintenance pain and time!
COMP2511: Refactoring 4
Code Smells: Possible Indicators
v Duplicated code
v Poor abstraction (change one place → must change others)
v Large loop, method, class, parameter list; deeply nested loop
v Class has too little cohesion
v Modules have too much coupling
v Class has poor encapsulation
v A subclass doesn’t use majority of inherited functionalities
v A “data class” has little functionality
v Dead code
v Design is unnecessarily general
v Design is too specific
COMP2511: Refactoring 5
Low-level refactoring
v Names:
v Renaming (methods, variables)
v Naming (extracting) “magic” constants
v Procedures:
v Extracting code into a method
v Extracting common functionality (including duplicate code) into a class/method/etc.
v Changing method signatures
v Reordering:
v Splitting one method into several to improve cohesion and readability
(by reducing its size)
v Putting statements that semantically belong together near each other
v For more, see http://www.refactoring.com/catalog/
COMP2511: Refactoring 6
IDEs support low-level refactoring
v Renaming:
• Variable, method, class.
v Extraction:
• Method, constant
• Repetitive code snippets
• Interface from a type
v Inlining: method, etc.
v Change method signature.
v Warnings about inconsistent code.
COMP2511: Refactoring 7
Higher-level refactoring
v Refactoring to design patterns.
v Changing language idioms (safety, brevity).
v Performance optimization.
v Generally high-level refactoring is much more important,
but unfortunately not well-supported by tools.
COMP2511: Refactoring 8
Code Smells
2
© Aarthi Natarajan, 2018
Smells : Design aspects that violate fundamental design
principles and impact software quality
Smells occur at different levels of granularity
– Code Smells: Structures in implementation of code such
as large methods, classes with multiple responsibilities,
complex conditional statements that lead to poor code
– Design Smells: Design aspects at a higher level of
abstraction (class level abstractions) such as classes with
multiple responsibilities, refused bequest
Regardless of the granularity, smells in general indicate
violation of software design principles, and eventually lead
to code that is rigid, fragile and require “refactoring”
Code and Design Smells
© Aarthi Natarajan, 2018
Bloaters: Code, Methods and classes that have grown in size, that
they are hard to work with
– Long Method, Large Class, Long Parameter List, Data Clumps
OO Abusers: Result from incorrect or incomplete application of OO
principles
– Switch statements, Refused Bequest
Change Preventers: Code changes are difficult (rigid code)
– Divergent change, Shot Gun Surgery
Dispensables: Code that is pointless and unnecessary
– Comments, Data Class, Lazy Class, Duplicate code
Couplers: Excessive coupling between classes
– Feature Envy, Inappropriate intimacy, Message Chains
Smells
© Aarthi Natarajan, 2018
Fix smell, long method
• Reduce length of a method body via Extract Method
– More readable, Less code duplication
– Isolates independent parts of code, – errors are less likely
• If local variables and parameters interfere with extracting a method, use
– Replace Temp With Query
– Introduce Parameter Object
– Preserve Whole Object
• If the above doesn’t work, try moving the entire method to a separate
object via Replace Method with Method Object
• Replace Method with Method Object
• Conditional operators and loops are a good clue that code can be moved
to a separate method.
Smell: Long Method
© Aarthi Natarajan, 2018
– More readable code (
The new method
name should describe
the method’s purpose
)
– Less code duplication,
more reusability
– Isolates independent
parts of code,
meaning that errors
are less likely
– A very common
refactoring technique
for code smells
Refactoring Techniques – Extract Method
© Aarthi Natarajan, 2018
– Methods contain a repeating group of parameters, causing
code duplication
– Consolidate these parameters into a separate class
• Also helps to move the methods for handling this data
• Beware, if only data is moved to a new class and
associated behaviours are not moved, this begins to
smell of a Data Class
– Eliminates smell such as Long Parameter List, Data Clumps,
Primitive Obsession, Long Method
Refactoring Techniques: Introduce Parameter Object
© Aarthi Natarajan, 2018
Often, we place the result of an expression in a local variable for later
use in the code
With Replace Temp With Query we:
• Move the entire expression to a separate method and return
the result from it.
• Query the method instead of using a variable
• Reuse the new method in other methods
• Eliminates smell such as Long Method, Duplicate Code
Refactoring Technique: Replace Temp With Query
double calculateTotal() {
double basePrice = quantity * itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
}
else {
return basePrice * 0.98;
}
}
double calculateTotal() {
if (basePrice() > 1000) {
return basePrice() * 0.95; }
else {
return basePrice() * 0.98; } }
double basePrice() {
return quantity * itemPrice;
}
}
© Aarthi Natarajan, 2018
• Having all the phone details in class Customer is not a
good OO design and also breaks SRP
• Refactor into two separate classes, each with its
appropriate responsibility
Refactoring Technique: Extract Class
© Aarthi Natarajan, 2018
• Problem:
• Similar to Long Method
• Usually violates Single Responsibility Principle
• May have
– A large number of instance variables
– Several methods
• Typically lacks cohesion and potential for duplicate code smell
Solution:
• Bundle group of variables via Extract Class or Extract Sub-Class
Smell: Large Class
© Aarthi Natarajan, 2018
Problem: Calling a query method and passing its results as the
parameters of another method, while that method could call the
query directly
• Too many parameters to remember
• Bad for readability, usability and maintenance
Solution:
• try placing a query call inside the method body via replace
parameter with method and remove parameters with change
method signature
• Eliminates smell such as Long Method, Duplicate Code
Code Smell: Long Parameter List
© Aarthi Natarajan, 2018
Problem:
• Different parts of the code contain identical groups of variables
e.g., fields in many classes, parameters in many method
signatures
• Can lead to code smell Long Parameter List
Solution: Move the behaviour to the data class via Move Method
• If repeating data comprises the fields of a class, use Extract
Class to move the fields to their own class.
• If the same data clumps are passed in the parameters of
methods, use Introduce Parameter Object to set them off
as a class.
• If some of the data is passed to other methods, think about
passing the entire data object to the method instead of just
individual fields Preserve Whole Object will help with this.
Code Smell: Data Clumps
© Aarthi Natarajan, 2018
Problem:
• A subclass uses only some of the methods and properties
inherited from its parents
• The unneeded methods may simply go unused or be redefined
and give off exceptions
• Often caused by creating inheritance between classes only by
the desire to reuse the code in a super-class
Code Smell: Refused Bequest
© Aarthi Natarajan, 2018
Solution:
• If inheritance makes no sense and the subclass really does have
nothing in common with the superclass, eliminate inheritance in
favour of Replace Inheritance with Delegation
• If inheritance is appropriate, but super class contains fields and
methods not applicable to all classes, then consider the following
options
– Create a new subclass
– Apply Push Down Field to move field relevant only to subclass
from superclass
– Apply Push Down Method to move behaviour from super class to
sub class, as behaviour makes sense only to sub class
– Often, you may apply an Extract Sub-Class Class to combine the
above steps
Code Smell: Refused Bequest
© Aarthi Natarajan, 2018
class Camel does not use field model. It
should be pushed down to class Car
public abstract class Transport {
// Push Down Field
private String model;
// Push Down Method
public String getModel() throws Exception
{
return model;
}
…
}
public class Car extends Transport { … }
public class Camel extends Transport {
…
public String getModel() {
throw new NotSupportedException();
}
}
public abstract class Transport {
…
}
Refused Bequest Example
// Use Push Down Field to move field and
// Push Down Method to move behaviour
// only relevant to sub class
// from super class to sub class
public abstract class Transport {
…
}
public class Car extends Transport
{
private String model;
public String getModel()
{
return model;
}
…
}
public class Camel extends Transport
{
…
}
© Aarthi Natarajan, 2018
Code Fragments look similar
• If the same code is found in two or more methods in the same class:
use Extract Method and place calls for the new method in both places
• If the same code is found in two subclasses of the same level:
– Use Extract Method for both classes, followed by Pull Up Field for
the fields used in the method that you are pulling up.
– If the duplicate code is inside a constructor, use Pull Up Constructor
Body
– If the duplicate code is similar but not completely identical, use Form
Template Method
– If two methods do the same thing but use different algorithms, select
the best algorithm and apply Substitute Algorithm
• If duplicate code is found in two different classes:
– If the classes are not part of a hierarchy, use Extract SuperClass in
order to create a single superclass for these classes that maintains all
the previous functionality
Code Smell: Duplicate Code
© Aarthi Natarajan, 2018
Problem: A method that is more interested in a class other than the
one it actually is
• Invokes several methods on another object to calculate some value
• Creates unnecessary coupling between the classes
Solution: A goal of OO design is to put the methods with its
associated data
– So the method must moved to the relevant class via Move Method
• If only part of a method accesses the data of another object,
use Extract Method followed by Move Method to move the part in
question
• If a method uses functions from several other classes, first
determine which class contains most of the data used. Then place
the method in this class along with the other data.
Code Smell: Feature Envy
© Aarthi Natarajan, 2018
Divergent Change: One class is changed in different ways for
different reasons
• Solution: Any change to handle a variation should change a single
class, and all the typing in the new class should express the
variation.
• To clean this up you identify everything that changes for a
particular cause and use Extract Class to put them all together
Shot Gun Surgery: A small change in the code forces lots of little
changes to different classes
• Solution:
– Use Move Method or Move Field to put all the changes into a
single class
– Often you can use Inline Class to bring a whole bunch of
behaviour together.
• Divergent change is one class that suffers many kinds of changes,
and shotgun surgery is one change that alters many classes.
Code Smell: Divergent Change, Shot Gun Surgery
© Aarthi Natarajan, 2018
Problem: Classes that just have attributes with setters and getters
and no behaviour
One of the goals of OO design is to put behaviour where the data is
Solution: Move the behaviour to the data class via Move Method
Code Smell: Data Classes
© Aarthi Natarajan, 2018
Problem: Classes that aren’t doing much to justify their existence
(maintenance overhead)
Subclasses without any overridden methods or additional fields can be lazy
classes as well
Solution:
• Move the data (postcode) from lazy class PostCode to the class
Address
• Delete the lazy class
Code Smell: Lazy classes
© Aarthi Natarajan, 2018
Problem: Switch statements are bad from an OO design point of view
Solution: Replace switch statements with a polymorphic solution
based on Strategy Pattern applying a series of refactoring techniques
( Extract Method, Move Method, Extract Interface etc., Refer lecture
demo for complete solution )
Code Smell: Switch Statements
© Aarthi Natarajan, 2018
Move Field/Method
Extract Class/Inline Class
Extract Method
Inline Method/Temporary Variable
Replace Temp with Query
Replace Method with Method Object
Rename Method
Substitute Algorithm
Introduce Parameter Object
Preserve Whole Object
Extract Sub Class/Super Class/Interface
Extract Method
Pull Up Field/Method/Constructor Body
Form Template Method
Replace Inheritance with Delegation
Replace Conditional with Polymorphism
List of Refactoring Techniques to be familiar
© Aarthi Natarajan, 2018
https://refactoring.guru/refactoring/smells
https://www.refactoring.com/catalog/
Useful Links