Software Construction
and Evolution
Bad Smells in Code
1
Observations on Bad Code Smells
• Done with an object-oriented design
– If design is procedural, can’t even do this
• A characteristic of a design that is a strong
indicator it has poor structure, and should
be refactored
• Code smells are rules of thumb
– Not always straightforward that a bad smell
must lead to a refactoring – must use judgment
Q3
2
Refactoring Related to Bad Smells
22 Bad Smells
– Situations to look out for
– “anti-patterns”
72 Refactorings
– What to do when you find them
– Often have design implications
Q2
3
3
Refactoring Indicators:
Bad Smells in Code
• Duplicated Code
• Long Method
• Large Class
• Long Parameter List
• Divergent Change
• Shotgun Surgery
• Feature Envy
• Data Clumps
• Primitive Obsession
• Switch Statements
• Lazy Class
Today!
4
4
Duplicated Code
• #1 Bad Smell – happens all the time…
• Situation 1: Same expression in two methods in
same class
• Solution 1: Make it a private ancillary routine and
parameterize it
– Use Extract Method
• Situation 2: Same code in two related classes
• Solution 2: Push commonalities into closest
mutual ancestor and parameterize
– Use Form Template Method for variation in subtasks Q4
5
5
Duplicated Code (continued)
• Situation 3: Same code in two unrelated classes
• Solution(s) for 3:
– Should classes be related?
• Introduce abstract parent (Extract Class)
– Does code really belong to just one class?
• Make the other class into a client (Extract Method)
– Can commonalities be separated out into subpart or
another function object?
• Make the method into a sub-object of both classes
• Use Strategy for polymorphic variation
(Replace method with method object)
6
6
Long Method
• Situation: Long Method in Class
– Trying to do too many things
– Poorly thought out abstractions and boundaries
– Micromanagement anti-pattern
• Solution: Think carefully about major tasks and how
they inter-relate. Aggressively:
– Break up into smaller private methods within the class
using Extract Method
– Delegate subtasks to subobjects that “know best” using
Extract Class/Method
• Replace data value with object Q6
7
7
Large Class
• Situation: Large Classes with too many subparts
and methods
• Two Step Solution:
1. Gather up the little pieces into aggregate subparts
(Extract class, replace data value with object)
2. Delegate methods to the new subparts
(Extract method)
• May have some unnecessary subparts
– Resist the urge to micromanage them!
– Counter example: Library classes
Q5
8
8
Long Parameter List
• Situation: Long parameter list in methods, making
them hard to understand
– Trying to do too much
– Too far from home
– Too many disparate subparts
• Solution(s):
– Trying to do too much?
• Break up into subtasks (Replace Param w/Method)
– Too far from home?
• Localize passing of parameters (Preserve Whole Object, Introduce
Parameter Object)
– Too many disparate subparts?
• Gather up parameters into aggregate sub-parts(Ditto -- Preserve and
Introduce object)
Q7
9
Divergent Change
• Situation: Class is commonly changed in
different ways for different reasons
– Class trying to do too much and contains too many
unrelated subparts
– Over time, some classes develop a “God complex”
– Sign of poor cohesion
• Solution:
– Break it up, reshuffle, reconsider relationships and
responsibilities (Extract Class)
10
Shotgun Surgery
• Situation: Each time you want to make a single,
seemingly coherent change, you have to change
lots of classes in little ways
– Opposite of divergent change …
– But also a sign of poor cohesion
• Solution:
– Look to do some gathering, either in a new or
existing class (Move method/field)
11
Feature Envy
• Situation: A method seems more interested in
another class than the one it’s defined in
– e.g., Method A::m() calls lots of get/set methods
of Class B
• Solution:
– Move A::m() (or part of it) into Class B!
(Move Method/Field, Extract Method)
– Exception: Visitor/iterator/strategy design pattern
where the whole point is to decouple the data from the
algorithm
Q8
12
Data Clumps
void Scene::setTitle (string titleText, int titleX, int titleY,
Colour titleColor){…}
void Scene::getTitle (string& titleText, int& titleX, int& titleY,
Colour& titleColor){…}
• Situation: You see a set of variables that seem to
“hang out” together
– e.g., passed as parameters, changed/accessed at the
same time
• Solution(s):
– Find clumps that appear as fields and turn them into
objects (Extract Class)
– Slim down method signatures (Intro. Param. Object or
Preserve Whole Object)
13
Primitive Obsession
• Situation: All object subparts are instances of
primitive types (int, string, bool, …)
– e.g., dates, currency, tel.#, ISBN, special string
values
• Solution:
– Create some “small classes” that can validate and
enforce the constraints
(Replace Data Value with Object, Extract Class,
Introduce Parameter Object)
Q9
14
Switch Statements
• Situation: Switch statements indicate misused
polymorphism and encapsulation, and results in
duplicates of switch statements across code
• Solution:
– Eliminate switches with redesigns using polymorphic
methods
(Replace conditional with polymorphism, replace type
code with subclasses)
15
Lazy Class
Situation: Classes that don’t do much that’s different
from other classes (distinct lack of diversity)
– Lazy classes are often results of ambitious design or
refactoring that gutted a class of useful behavior
• Solution:
– When several sibling classes don’t exhibit
polymorphic behavioral differences, consider just
collapsing them back into the parent and add some
parameters
(Collapse Hierarchy, Inline Class) Q10
16