Refactoring and Code Smell New
Refactoring and Code Smell New
Code Smells
If it Stinks, change it!
65
What is Refactoring?
67
What is Refactoring?
67
What is Refactoring?
67
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
What if you hear...
68
Why do we Refactor?
70
Why do we Refactor?
70
Why do we Refactor?
70
Why do we Refactor?...
71
Why do we Refactor?...
71
Why do we Refactor?...
71
Why do we Refactor?...
71
Why do we Refactor?...
71
Why do we Refactor?...
71
Readability
72
When should you refactor?
73
When should you refactor?
73
When should you refactor?
73
When should you refactor?
73
When should you refactor?
Like championship
refactor the design to make it simple to add
setting
refactor to understand the codeourselves up for
73
The Two Hats
Adding Function
Refactoring
Add new capabilities to the Does not add any new features
system
Does not add tests (but may change some)
Adds new tests
Restructure the code to remove
Get the test working redundancy
74
How do we Refactor?
77
2 Piece of Advice before Refactoring
78
2 Piece of Advice before Refactoring
Baby Steps
78
2 Piece of Advice before Refactoring
78
Code Smells?
79
Category of Code Smells
BLOATERS
Bloaters are code, methods and classes that have increased to such
gargantuan proportions that they are hard to work with. Usually these
smells do not crop up right away, rather they accumulate over time as the
program evolves (and especially when nobody makes an effort to
eradicate them).
• Long Method
• Large Class
• Primitive Obsession
• Long Parameter List
• Data Clumps
80
Category of Code Smells
DISPENSABLES
A dispensable is something pointless and unneeded whose absence
would make the code cleaner, more efficient and easier to understand.
• Comments
• Duplicate Code
• Lazy Class
• Dead Code
• Speculative Generality
• Oddball Solution
80
Category of Code Smells
COUPLERS
Coupler Code Smells, as the name indicates, couples code together too
tightly that makes change difficult. Software is supposed to change. That’s
literally the name, “soft” + ware. If it wasn’t meant to change then it
would just be “hard” + ware. By coupling software together too tightly,
you make change impossible, and have just effectively re-invented
hardware.
• Inappropriate Intimacy
• Indecent Exposure
• Feature Envy
• Message Chains
• Middle Man
80
Category of Code Smells
OBJECT ORIENTED ABUSERS/ ABUSERS
All these smells are incomplete or incorrect application of object-oriented
programming principles.
• Refused Bequest
• Switch Statements
• Alternative Classes with Different Interfaces
• Temporary Field
80
Category of Code Smells
CHANGE PREVENTERS
These smells mean that if you need to change something in one place in
your code, you have to make many changes in other places too. Program
development becomes much more complicated and expensive as a result.
• Divergent Change
• Parallel Inheritance Hierarchies
• Shotgun Surgery
80
Common Code Smells
Inappropriate Naming Long Method
Comments Long Parameter List
Dead Code Switch Statements
Duplicated code
Speculative Generality
Primitive Obsession
Oddball Solution
Large Class
Feature Envy
Lazy Class
Refused Bequest
Black Sheep
81
Inappropriate Naming
82
Inappropriate Naming
Names given to variables (fields) and methods should be clear and
meaningful.
82
Inappropriate Naming
Names given to variables (fields) and methods should be clear and
meaningful.
A variable name should say exactly what it is.
Which is better?
82
Inappropriate Naming
Names given to variables (fields) and methods should be clear and
meaningful.
A variable name should say exactly what it is.
Which is better?
82
Comments
83
Comment: “Grow the Array” smells
public class MyList
{ void AddToList(string element)
int INITIAL_CAPACITY = 10; {
bool m_readOnly; if (!m_readOnly)
int m_size = 0; {
int m_capacity; int newSize = m_size + 1;
string[] m_elements; if (newSize > GetCapacity())
{
public MyList() // grow the array
{ m_capacity += INITIAL_CAPACITY;
m_elements = new string[INITIAL_CAPACITY]; string[] elements2 = new string[m_capacity];
m_capacity = INITIAL_CAPACITY; for (int i = 0; i < m_size; i++)
} elements2[i] = m_elements[i];
84
Comment Smells Make-over
void AddToList(string element) private void Grow()
{ {
if (m_readOnly) m_capacity += INITIAL_CAPACITY;
return; string[] elements2 = new string[m_capacity];
if (ShouldGrow()) for (int i = 0; i < m_size; i++)
{ elements2[i] = m_elements[i];
Grow();
} m_elements = elements2;
StoreElement(element); }
}
private void StoreElement(string element)
{
m_elements[m_size++] = element;
}
private bool ShouldGrow()
{
return (m_size + 1) > GetCapacity();
}
85
Smell: Comments
Rename Method
86
Smell: Comments
Extract Method
87
Smell: Comments
Extract Method
void PrintOwning(double amount){
PrintBanner();
// print details
System.Console.Out.WriteLine(“name: “+ name);
System.Console.Out.WriteLine(“amount: “+ amount);
}
87
Smell: Comments
Extract Method
void PrintOwning(double amount){
PrintBanner();
// print details
System.Console.Out.WriteLine(“name: “+ name);
System.Console.Out.WriteLine(“amount: “+ amount);
}
89
Long Method
A method is long when it is too hard to quickly comprehend.
89
Long Method
A method is long when it is too hard to quickly comprehend.
Long methods tend to hide behavior that ought to be shared, which leads to
duplicated code in other methods or classes.
89
Long Method
A method is long when it is too hard to quickly comprehend.
Long methods tend to hide behavior that ought to be shared, which leads to
duplicated code in other methods or classes.
Good OO code is easiest to understand and maintain with shorter methods
with good names
89
Long Method
A method is long when it is too hard to quickly comprehend.
Long methods tend to hide behavior that ought to be shared, which leads to
duplicated code in other methods or classes.
Good OO code is easiest to understand and maintain with shorter methods
with good names
Remedies:
Extract Method
Replace Temp with Query
Introduce Parameter Object
Preserve Whole Object
Replace Method with Method Object.
Decompose Conditional
89
Long Method Example
private String toStringHelper(StringBuffer result)
{
result.append("<");
result.append(name);
result.append(attributes.toString());
result.append(">");
if (!value.equals(""))
result.append(value);
Iterator it = children().iterator();
while (it.hasNext())
{
TagNode node = (TagNode)it.next();
node.toStringHelper(result);
}
result.append("</");
result.append(name);
result.append(">");
return result.toString();
}
90
Long Method Makeover (Extract Method)
private String toStringHelper(StringBuffer result)
{ private void writeValueTo(StringBuffer result)
writeOpenTagTo(result); {
writeValueTo(result); if (!value.equals(""))
writeChildrenTo(result); result.append(value);
writeEndTagTo(result); }
return result.toString();
} private void writeChildrenTo(StringBuffer result)
{
private void writeOpenTagTo(StringBuffer result) Iterator it = children().iterator();
{ while (it.hasNext())
result.append("<"); {
result.append(name); TagNode node = (TagNode)it.next();
result.append(attributes.toString()); node.toStringHelper(result);
result.append(">"); }
} }
private void writeEndTagTo(StringBuffer result)
{
result.append("</");
result.append(name);
result.append(">");
}
91
Smell: Long Method
92
Smell: Long Method
92
Smell: Long Method
94
Smell: Long Method
95
Smell: Long Method
withinPlan = plan.withinRange(daysTempRange());
95
Smell: Long Method
96
Smell: Long Method
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation;
...
}
96
Smell: Long Method
Decompose Conditional
You have a complicated conditional (if-then-else) statement.
Extract methods from the condition, then part, and else parts.
if (date.before (SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;
else charge = quantity * _summerRate;
if (notSummer(date))
charge = winterCharge(quantity);
else charge = summerCharge (quantity);
97
Example of Conditional Complexity
98
Long Parameter List
Methods that take too many parameters produce client code that is
awkward and difficult to work with.
Remedies:
Introduce Parameter Object
Replace Parameter with Method
Preserve Whole Object
174
Example
private void createUserInGroup() {
GroupManager groupManager = new GroupManager();
Group group = groupManager.create(TEST_GROUP, false,
GroupProfile.UNLIMITED_LICENSES, "",
GroupProfile.ONE_YEAR, null);
user = userManager.create(USER_NAME, group, USER_NAME, "jack",
USER_NAME, LANGUAGE, false, false, new Date(),
"blah", new Date());
}
175
Smell: Long Parameter List
176
Smell: Long Parameter List
176
Smell: Long Parameter List
Customer
AmoutInvoicedIn(DateRange range)
AmoutRecivedIn(DateRange range)
AmoutOverdueIn(DateRange range)
176
Smell: Long Parameter List
177
Smell: Long Parameter List
withinPlan = plan.withinRange(daysTempRange());
Feature Envy
A method that seems more interested in some other class than the one it is in.
Data and behavior that acts on that data belong together. When a method
makes too many calls to other classes to obtain data or functionality, Feature
Envy is in the air.
Remedies:
Move Field
Move Method
Extract Method
178
Example
Public class CapitalStrategy{
double capital(Loan loan)
{
if (loan.getExpiry() == NO_DATE && loan.getMaturity() != NO_DATE)
return loan.getCommitmentAmount() * loan.duration() * loan.riskFactor();
return 0.0;
}
} 179
Smell: Feature Envy
Move Field
180
Smell: Feature Envy
Move Method
181
Dead Code
Accidental Changes.
More Dead Code
Remedies
114
Dead Code Example
A Loan class contains five constructors, three of which are shown below:
public Loan(double commitment, double outstanding, int customerRating, Date maturity, Date expiry) {
this(null, commitment, outstanding, customerRating, maturity, expiry); }
public Loan(CapitalStrategy capitalStrategy, double commitment, int riskRating, Date maturity, Date expiry) {
this(capitalStrategy, commitment, 0.00, riskRating, maturity, expiry); } ... }
115
Duplicated Code
The most pervasive and pungent smell in software
There is obvious or blatant duplication
Such as copy and paste
There are subtle or non-obvious duplications
Such as parallel inheritance hierarchies.
Similar algorithms
Remedies
Extract Method
Pull Up Field
Form Template Method
Substitute Algorithm
122
Ctl+C Ctl+V Pattern
123
Example Of Obvious Duplication
124
126
Levels of Duplication
127
Literal Duplication
128
Semantic Duplication
for(int i : asList(1,3,5,10,15))
stack.push(i);
129
Data Duplication
130
Conceptual Duplication
132
Logical Steps - Duplication
134
Smell: Duplicate Code
Pull Up Field
136
Smell: Duplicate Code
137
Smell: Duplicate Code
Substitute Algorithm
138
Smell: Duplicate Code
Substitute Algorithm
String foundPerson(String[] people){
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
return "Don";
}
if (people[i].equals ("John")){
return "John";
}
if (people[i].equals ("Kent")){
return "Kent";
}
}
return ""; }
138
Smell: Duplicate Code
Substitute Algorithm
String foundPerson(String[] people){
138
Speculative Generality
You get this smell when people say "Oh, I think we will need the ability to do that
someday" and thus want all sorts of hooks and special cases to handle things that
aren't required.
This odor exists when you have generic or abstract code that isn’t actually
needed today. Such code often exists to support future behavior, which may or may
not be necessary in the future.
Remedies
Collapse Hierarchy
Inline Class
Remove Parameter
105
Smell: Speculative Generality
Collapse Hierarchy
Salesman
104
Smell: Speculative Generality
Inline Class
109
Smell: Speculative Generality
Remove Parameter
110
Lazy Class
A class that isn't doing enough to carry its weight
We let the class die with dignity
Often this might be a class that used to pay its way but has been downsized
with refactoring. Or it might be a class that was added because of changes that
were planned but not made.
Remedies
Inline Class
Collapse Hierarchy
99
Lazy Clazz Example
public interface SomeInterface {
void methodOne();
void defaultMethod();
}
public abstract class LazyClazz implements SomeInterface {
public abstract void methodOne();
public void defaultMethod() {
//do nothing
}
}
public class WorkerClazz extends LazyClazz {
public void methodOne() {
// some actual code here
}
public void defaultMethod() {
//some more actual code
}
}
100
Another Lazy Class
public class Letter {
private final String content;
Inline Class
103
Smell: Lazy Class
Collapse Hierarchy
Salesman
104
Refused Bequest
This rather potent odor results when subclasses inherit code that they don’t want.
In some cases, a subclass may “refuse the bequest” by providing a do-nothing
implementation of an inherited method.
Remedies
Push Down Field
Push Down Method
116
Smell: Refused Bequest
Salesman
104
Smell: Refused Bequest
104
Black Sheep
118
Example
119
Primitive Obsession
This smell exists when primitives, such as strings, doubles, arrays or low-level
language components, are used for high-level operations instead of using classes.
This typically occurs when you haven’t yet seen how a higher-level
abstraction can clarify or simplify your code.
Remedies
Extract Class
Replace Data Value with Object
Replace Type Code with Class
Introduce Parameter Object
Replace Array with Object
160
Primitive Obsession Example
if (someString.indexOf("substring") != -1)
if(someString.contains("substring"))
161
Primitive Obsession Example
private void Grow() {
Object[] newElements = new Object[elements.length + 10];
for (int i = 0; i < size; i++)
newElements[i] = elements[i];
elements = newElements;
}
161
Primitive Obsession Example
public class CompositeShape
{
IShape [] arr = new IShape[100];
int count = 0;
163
Smell: Primitive Obsession
167
Smell: Primitive Obsession
167
Oddball Solution
When a problem is solved one way throughout a system and the same problem is
solved another way in the same system, one of the solutions is the oddball or
inconsistent solution. The presence of this smell usually indicates subtly duplicated
code.
168
Oddball Solution Example
string LoadUserProfileAction::process()
{
//some code here
return process("ViewAction");
}
string UploadAction::process() {
//some code here
return process("ViewAction");
}
string ShowLoginAction::process() {
//some other code here
Action* viewAction = actionProcessor().get("ViewAction");
return viewAction->process();
}
169
Oddball Solution Example
private void grow() {
Object[] newElements = new Object[elements.length + 10];
for (int i = 0; i < size; i++)
newElements[i] = elements[i];
elements = newElements;
}
170
Smell: Odd Ball Solution
Substitute Algorithm
String foundPerson(String[] people){
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
return "Don";
}
if ("John".equals (people[i])){
return "John";
}
if (people[i].equals ("Kent")){
return "Kent";
}
}
return ""; }
171
Smell: Odd Ball Solution
Substitute Algorithm
String foundPerson(String[] people){
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
return "Don";
}
if ("John".equals (people[i])){
return "John";
}
if (people[i].equals ("Kent")){
return "Kent";
}
}
return ""; } String foundPerson(String[] people){ List candidates =
Arrays.asList(new String[] {"Don", "John", "Kent"});
for (String person : people)
if (candidates.contains(person))
return person;
return ""; }
171
Large Class
Like people, classes suffer when they take on too many responsibilities.
GOD Objects
Fowler and Beck note that the presence of too many instance variables usually
indicates that a class is trying to do too much. In general, large classes typically
contain too many responsibilities.
Remedies
Extract Class
Replace Type Code with Class/Subclass
Replace Type Code with State/Strategy
Replace Conditional with Polymorphism
152
153
153
Smell: Large Class
Extract Class
154
Smell: Large Class
155
Smell: Large Class
156
Smell: Large Class
157
Smell: Large Class
158
Switch Statement
This smell exists when the same switch statement (or “if…else if…else if”
statement) is duplicated across a system.
Such duplicated code reveals a lack of object-orientation and a missed
opportunity to rely on the elegance of polymorphism.
Remedies:
Replace Type Code with Polymorphism
Replace Type Code with State / Strategy
Replace Parameter with Explicit Methods
Introduce Null Object.
139
Switch Smell Examples
140
More Switch Smell Examples
142
Evil Switch Example
143
Smell: Switch Smell
144
Smell: Switch Smell
145
Smell: Switch Smell
void setHeight(int h) {
this.height = h;
}
void setWidth (int w) {
this.width = w;
}
145
Refactoring & Patterns
There is a natural relation between patterns and refactorings. Patterns are where
you want to be; refactorings are ways to get there from somewhere else. - Martin
Fowler
182
Reference Reading
185
Further Information On
Code Smells and Refactoring
186
References
187