0% found this document useful (0 votes)
134 views

Refactoring and Code Smell New

The document discusses refactoring code and code smells. It defines refactoring as making small changes to the internal structure of code without changing its external behavior. This helps improve code design, minimize technical debt, and make code easier to understand and maintain over time. The document also categorizes different types of code smells, or design problems, that occur frequently, such as code that is too large, duplicate code, and code with tight coupling that makes changes difficult. Refactoring helps address these code smells and keep code healthy.

Uploaded by

lisso
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
134 views

Refactoring and Code Smell New

The document discusses refactoring code and code smells. It defines refactoring as making small changes to the internal structure of code without changing its external behavior. This helps improve code design, minimize technical debt, and make code easier to understand and maintain over time. The document also categorizes different types of code smells, or design problems, that occur frequently, such as code that is too large, duplicate code, and code with tight coupling that makes changes difficult. Refactoring helps address these code smells and keep code healthy.

Uploaded by

lisso
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 144

Refactoring

Code Smells
If it Stinks, change it!

65
What is Refactoring?

67
What is Refactoring?

small steps, each of which changes the program’s


A series of

internal structure without changing its external


behavior - Martin Fowler

67
What is Refactoring?

small steps, each of which changes the program’s


A series of

internal structure without changing its external


behavior - Martin Fowler
Verify no change in external behavior by
Testing
Using the right tool - IDE
Formal code analysis by tool
Being very, very careful

67
What if you hear...

68
What if you hear...

We’ll just refactor the code to support logging

68
What if you hear...

We’ll just refactor the code to support logging

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication
This class is too big, we need to refactor it

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication
This class is too big, we need to refactor it

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication
This class is too big, we need to refactor it
Caching?

68
What if you hear...

We’ll just refactor the code to support logging


Can you refactor the code so that it authenticates against LDAP instead of
Database?
We have too much duplicate code, we need to refactor the code to eliminate
duplication
This class is too big, we need to refactor it
Caching?

68
Why do we Refactor?

70
Why do we Refactor?

Helps us deliver more business value faster

70
Why do we Refactor?

Helps us deliver more business value faster


Improves the design of our software
Combat’s “bit rot”
Easier to maintain and understand
Easier to facilitate change
More flexibility
Increased re-usability

70
Why do we Refactor?...

71
Why do we Refactor?...

Minimizes technical debt

71
Why do we Refactor?...

Minimizes technical debt


Keep development at speed

71
Why do we Refactor?...

Minimizes technical debt


Keep development at speed
To make the software easier to understand
Write for people, not the compiler
Understand unfamiliar code

71
Why do we Refactor?...

Minimizes technical debt


Keep development at speed
To make the software easier to understand
Write for people, not the compiler
Understand unfamiliar code
To help find bugs
refactor while debugging to clarify the code

71
Why do we Refactor?...

Minimizes technical debt


Keep development at speed
To make the software easier to understand
Write for people, not the compiler
Understand unfamiliar code
To help find bugs
refactor while debugging to clarify the code
To “Fix broken windows” - Pragmatic Programmers

71
Readability

Which code segment is easier to read?


Sample 1
if (date.Before(Summer_Start) || date.After(Summer_End)){
charge = quantity * winterRate + winterServiceCharge;
else charge = quantity * summerRate;
}
Sample 2
if (IsSummer(date)) {
charge = SummerCharge(quantity);
else charge = WinterCharge(quantity);
}

72
When should you refactor?

73
When should you refactor?

To add new functionality


refactor existing code until you understand it
refactor the design to make it simple to add

73
When should you refactor?

To add new functionality


refactor existing code until you understand it
refactor the design to make it simple to add
To find bugs
refactor to understand the code

73
When should you refactor?

To add new functionality


refactor existing code until you understand it
refactor the design to make it simple to add
To find bugs
refactor to understand the code
For code reviews
immediate effect of code review
allows for higher level suggestions

73
When should you refactor?

To add new functionality


refactor existing code until you understand it

Like championship
refactor the design to make it simple to add

To find bugs snooker players we are

setting
refactor to understand the codeourselves up for

For code reviews our next shot


immediate effect of code review

allows for higher level suggestions

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?

We looks for Code-Smells


Things that we suspect are not quite right or will cause us severe pain if we do
not fix

77
2 Piece of Advice before Refactoring

78
2 Piece of Advice before Refactoring

Baby Steps

78
2 Piece of Advice before Refactoring

The Hippocratic Oath


First Do No Harm!
Baby Steps

78
Code Smells?

Code Smells identify frequently occurring design problems in a way


that is more specific or targeted than general design guidelines (like
“loosely coupled code” or “duplication-free code”). - Joshua K
A code smell is a design that duplicates, complicates, bloats or tightly
couples code

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?

private string s; OR private string salary;

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?

private string s; OR private string salary;


A method should say exactly what it does.
Which is better?

public double calc (double s)


public double calculateFederalTaxes (double salary)

82
Comments

Comments are often used as deodorant


Comments represent a failure to express an idea in the code. Try to make your code
self-documenting or intention-revealing
When you feel like writing a comment, first try "to refactor so that the
comment becomes superfluous.
Remedies:
Extract Method
Rename Method
Introduce Assertion

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];

int GetCapacity() { m_elements = elements2;


return m_capacity; }
} m_elements[m_size++] = element;
} }
}

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);
}

void PrintOwning(double amount){


PrintBanner();
PrintDetails(amount);
}

void PrintDetails(double amount){


System.Console.Out.WriteLine(“name: “+ name);
System.Console.Out.WriteLine(“amount: “+ amount);
}
87
Long Method

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

Replace Temp with Query

double basePrice = _quanity * _itemPrice;


if(basePrice > 1000) {
return basePrice * 0.95;
}
else {
return basePrice * 0.98;
}

92
Smell: Long Method

Replace Temp with Query

if(getBasePrice() > 1000) {


double basePrice = _quanity * _itemPrice; return getBasePrice() * 0.95;
if(basePrice > 1000) { }
else {
return basePrice * 0.95; return getBasePrice() * 0.98;
} }
else {
return basePrice * 0.98; double getBasePrice() {
} return _quanitiy * itemPrice;
}

92
Smell: Long Method

Introduce Parameter Object

94
Smell: Long Method

Preserve Whole Object

int low = daysTempRange().getLow();


int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);

95
Smell: Long Method

Preserve Whole Object

int low = daysTempRange().getLow();


int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);

withinPlan = plan.withinRange(daysTempRange());

95
Smell: Long Method

Replace Method with Method Object


//class Order...
double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation;
...
}

96
Smell: Long Method

Replace Method with Method Object


//class Order...
double price() {

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

Introduce Parameter Object

176
Smell: Long Parameter List

Introduce Parameter Object


Customer

AmoutInvoicedIn(Date start, Date end)


AmoutRecivedIn(Date start, Date end)
AmoutOverdueIn(Date start, Date end)

176
Smell: Long Parameter List

Introduce Parameter Object


Customer

AmoutInvoicedIn(Date start, Date end)


AmoutRecivedIn(Date start, Date end)
AmoutOverdueIn(Date start, Date end)

Customer

AmoutInvoicedIn(DateRange range)
AmoutRecivedIn(DateRange range)
AmoutOverdueIn(DateRange range)

176
Smell: Long Parameter List

Replace Parameter with Method


public double getPrice() {
int basePrice = _quantity * _itemPrice;
int discountLevel;
if (_quantity > 100)
discountLevel = 2;
else
discountLevel = 1;
double finalPrice = discountedPrice (basePrice, discountLevel);
return finalPrice;
}

private double discountedPrice (int basePrice, int discountLevel) {


if (discountLevel == 2)
return basePrice * 0.1;
else
return basePrice * 0.05;
177
Smell: Long Parameter List

Replace Parameter with Method


public double getPrice() {
int basePrice = _quantity * _itemPrice;
int discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice, discountLevel);
return finalPrice;
}

private int getDiscountLevel() {


if (_quantity > 100) return 2;
else return 1;
}
private double discountedPrice (int basePrice, int discountLevel) {
if (getDiscountLevel() == 2) return basePrice * 0.1;
else return basePrice * 0.05;
}
177
Smell: Long Parameter List

Replace Parameter with Method

public double getPrice() {


int basePrice = _quantity * _itemPrice;
int discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice);
return finalPrice;
}

private double discountedPrice (int basePrice) {


if (getDiscountLevel() == 2) return basePrice * 0.1;
else return basePrice * 0.05;
}

177
Smell: Long Parameter List

Preserve Whole Object

int low = daysTempRange().getLow();


int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);
Smell: Long Parameter List

Preserve Whole Object

int low = daysTempRange().getLow();


int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);

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();

if (loan.getExpiry() != NO_DATE && loan.getMaturity() == NO_DATE)


{
if (loan.getUnusedPercentage() != 1.0)
return loan.getCommitmentAmount() * loan.getUnusedPercentage() *
loan.duration() * loan.riskFactor();
else
return (loan.outstandingRiskAmount() * loan.duration() * loan.riskFactor()) +
(loan.unusedRiskAmount() * loan.duration() * loan.unusedRiskFactor());
}

return 0.0;
}
} 179
Smell: Feature Envy

Move Field

180
Smell: Feature Envy

Move Method

181
Dead Code

Code that is no longer used in a system or related system is Dead Code.


Increased Complexity.

Accidental Changes.
More Dead Code
Remedies

114
Dead Code Example

A Loan class contains five constructors, three of which are shown below:

public class Loan…


public Loan(double commitment, int riskRating, Date maturity, Date expiry) { this(commitment, 0.00,
riskRating, maturity, expiry); }

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); } ... }

One of the above constructors is never called by a client. It is dead code.

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

Same for loop in 2 places

128
Semantic Duplication

1stLevel - For and For Each Loop stack.push(1); stack.push(3);


stack.push(5); stack.push(10);
stack.push(15);
2ndLevel - Loop v/s Lines repeated v/s

for(int i : asList(1,3,5,10,15))
stack.push(i);

129
Data Duplication

Some constant declared in 2 classes (test and


production)

130
Conceptual Duplication

2 Algorithm to Sort elements (Bubble sort and Quick sort)

132
Logical Steps - Duplication

Same set of steps repeat in different scenarios.


Ex: Same set of validations in various points in your
applications

134
Smell: Duplicate Code

Pull Up Field

136
Smell: Duplicate Code

Form Template Method

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){

for (int i = 0; i < people.length; i++) {


if (people[i].equals ("Don")){
return "Don";
} String foundPerson(String[] people){
if (people[i].equals ("John")){ List candidates = Arrays.asList(new String[] {"Don",
return "John"; "John", "Kent"});
} for (String person : people)
if (people[i].equals ("Kent")){ if (candidates.contains(person))
return "Kent"; return person;
} return "";
} }
return "";
}

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;

public Letter(String content) {


this.content = content;
}

public String getContent() {


return content;
}
}
102
Smell: Lazy Class

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

Example of Refused Bequest

Salesman

104
Smell: Refused Bequest

Refused Bequest Make Over

104
Black Sheep

Sometimes a subclass or method doesn't fit in so well with its family.


A subclass that is substantially different in nature than other subclasses in the
hierarchy.
A method in a class that is noticeably different from other methods in the class.

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;
}

private void Grow() {


Object[] newElements = new Object[elements.length + INITIAL_CAPACITY];
System.arraycopy(elements, 0, newElements, 0, size);
elements = newElements;
}

161
Primitive Obsession Example
public class CompositeShape
{
IShape [] arr = new IShape[100];
int count = 0;

public void Add(IShape shape){


arr[count++] = shape;
}

public void Remove(IShape shape)


{
for (int i = 0; i < 100; i++)
{
if (shape == arr[i])
{
//code to remove
}
}
}
161
Primitive Obsessed Code - Make Over
public class CompositeShape
{
List<IShape> shapeList = new List<IShape>();

public void Add(IShape shape)


{
shapeList.Add(shape);
}

public void Remove(IShape shape)


{
shapeList.Remove(shape);
}
}

163
Smell: Primitive Obsession

Replace Array with Object


String[] row = new String[3];
row [0] = "Liverpool";
row [1] = "15";

167
Smell: Primitive Obsession

Replace Array with Object


String[] row = new String[2];
row [0] = "Liverpool";
row [1] = "15";

Performance row = new Performance("Liverpool", "15");

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;
}

private void anotherGrow() {


Object[] newElements = new Object[elements.length + INITIAL_CAPACITY];
System.arraycopy(elements, 0, newElements, 0, size);
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

Replace Type Code with Class

155
Smell: Large Class

Replace Type Code with Subclasses

156
Smell: Large Class

Replace Type Code with State/Strategy

157
Smell: Large Class

Extract (Narrow) Interface

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

Replace Type Code with Polymorphism

144
Smell: Switch Smell

Replace Parameter with Method


void setValue (String name, int value) {
if (name.equals("height"))
this.height = value;
else if (name.equals("width"))
this.width = value;
}

145
Smell: Switch Smell

Replace Parameter with Method


void setValue (String name, int value) {
if (name.equals("height"))
this.height = value;
else if (name.equals("width"))
this.width = value;
}

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

Wiki Discussion About Code Smells: http://c2.com/cgi/wiki?CodeSmell


Mika’s Smell Taxonomy: http://www.soberit.hut.fi/mmantyla/
BadCodeSmellsTaxonomy.htm
Bill Wake’s book, “Refactoring Workbook”
Refactoring Catalog Online: http://www.refactoring.com/catalog/index.html
Refactoring to Patterns Catalog Online: http://industriallogic.com/xp/
refactoring/catalog.html

186
References

[F] Fowler, Martin. Refactoring: Improving the Design of Existing Code.


Boston, MA: Addison-Wesley, 2000
[K] Kerievsky, Joshua. Refactoring to Patterns. Boston, MA: Addison-Wesley,
2005

187

You might also like