refactoring for software design smells - icse 2014 tutorial
DESCRIPTION
This tutorial on refactoring was software design smells was presented in ICSE 2014.TRANSCRIPT
Girish Suryanarayana, Ganesh Samarthyam, Tushar Sharma
2
Who we are?
Girish Suryanarayana
Tushar Sharma
Ganesh Samarthyam
3
Outline
Introduction – Design Quality, Technical Debt, and Design Smells
Design Smells Catalog – Examples and corresponding Refactoring
The Smell Ecosystem and Repaying Technical Debt in Practice
4
Outline
Introduction – Design Quality, Technical Debt, and Design Smells
Design Smells Catalog – Examples and corresponding Refactoring
The Smell Ecosystem and Repaying Technical Debt in Practice
Capers Jones on design errors in industrial software
* http://sqgne.org/presentations/2012-13/Jones-Sep-2012.pdf
0
20
40
60
80
100
120
IBM Corportation
(MVS)
SPR Corporation (Client Studies)
TRW Corporation
MITRE Corporation
Nippon Electric Corp
Pe
rce
nta
ge C
on
trib
uti
on
Industry Data on Defect Origins
Adminstrative Errors
Documentation Errors
Bad Fixes
Coding Errors
Design Errors
Requirements Errors
Up to 64% of software defects can be traced back to errors in software
design in enterprise software!
Why care about design quality?
Poor software quality costs more than $150 billion per year in U.S. and greater than $500 billion per year worldwide
The debt that accrues when you knowingly or unknowingly make wrong or non-optimal design decisions
Software Quality
Technical Debt
Design Quality
Design Quality means changeability, extensibility,
understandability, reusability
7
Why care about technical debt?
8
What constitutes technical debt?
…
Code debt
Static analysis tool
violations
Inconsistent coding style
Design debt
Design smells
Violations of design rules
Test debt
Lack of tests
Inadequate test coverage
Documentation debt
No documentation for important
concerns
Outdated documentation
“Design smells” aka…
“Smells are certain structures in the code that suggest (sometimes they scream for) the possibility of refactoring.”
What is a smell?
10
Why care about smells?
Impacted Quality
Reusability
Changeability
Understandability
Extensibility
Testability
Reliability
Product Quality
Design Quality
Design Smells
Impacted Quality
Maintainability:
Affected by
changeability &
extensibility
Reliability: Impacted
by poor
understandability
…
Indicators
Rigidity & Fragility
Immobility & Opacity
Needless complexity
Needless repetition
…
11
Why we focus on smells?
A good designer is one who knows the
design solutions
A GREAT designer is one who understands the impact of design
smells and knows how to address them
12
Design Smells as violations of fundamental principles
What do smells indicate?
Violations of fundamental design principles
We use Booch’s fundamental principles for classification and naming of
smells
This helps identify cause of the smell and potential refactoring as well
13
Design principles used to classify design smells
Abstraction Encapsulation
Modularization Hierarchy
Principles
14
A principle-based approach to design smells classification
Related Publications
S G Ganesh, Tushar Sharma, Girish Suryanarayana. Towards a Principle-based
Classification of Structural Design Smells. In Journal of Object Technology, vol.
12, no. 2, 2013, pages 1:1–29.doi:10.5381/jot.2013.12.2.a1
URL: http://www.jot.fm/issues/issue_2013_06/article1.pdf (open access)
15
Summary till now
Design Quality
Technical Debt
Design Smells
Why care about smells
16
Outline
Introduction – Design Quality, Technical Debt, and Design Smells
Design Smells Catalog – Examples and corresponding Refactoring
The Smell Ecosystem and Repaying Technical Debt in Practice
17
18
A note on examples in this presentation
We cover only a few examples of each smell category in this presentation
Lack of time
Most examples are from OpenJDK 7.0 (open source)
All illustrations are mostly as UML diagrams so no need to know Java
(though you’ll appreciate more if you know Java)
Almost all examples are UML-like diagrams – so agnostic of OO language
Some code examples are in Java, but they are very few
19
20
The principle of abstraction
21
Enabling techniques for abstraction
22
23
Incomplete abstraction
This smell arises when a type does not support a responsibility
completelySpecifically, the public interface of the type is incomplete in that it
does not support all behavior needed by objects of its type
24
Incomplete abstraction – Example
In this case, the MutableTreeNode
supports only setUserObject but no
corresponding getUserObject (which
is provided in its derived class!) Hence, MutableTreeNode has
Incomplete Abstraction smell
How to fix it? Provide all the
necessary and relevant methods
required for satisfying a
responsibility completely in the class
itself
In case of public APIs (as in this
case), it is often “too late” to fix
it!
25
Another example
26
27
How to refactor & in future avoid this smell?
For each abstraction (especially in public interface) look out for symmetrical
methods or methods that go together
For example, methods for comparing equality of objects and getting
hash code (in Java/C#)
Look out for missing matching methods in symmetrical methods (see
table)
min/max open/close create/destroy get/set
read/write print/scan first/last begin/end
start/stop lock/unlock show/hide up/down
source/target insert/delete first/last push/pull
enable/disable acquire/release left/right on/off
28
29
Duplicate abstraction
This smell arises when two or more abstractions have identical
names or identical implementation or both.
30
31
Kinds of clones
• exactly identical except for variations in whitespace, layout, and comments
Type 1
• syntactically identical except for variation in symbol names, whitespace, layout, and comments
Type 2
• identical except some statements changed, added, or removed
Type 3
• when the fragments are semantically identical but implemented by syntactic variants
Type 4
32
public class FormattableFlags {
// Explicit instantiation of this class is prohibited.
private FormattableFlags() {}
/** Left-justifies the output. */
public static final int LEFT_JUSTIFY = 1<<0; // '-'
/** Converts the output to upper case */
public static final int UPPERCASE = 1<<1; // 'S'
/**Requires the output to use an alternate form. */
public static final int ALTERNATE = 1<<2; // '#'
}
33
public class Dollar {public static final String symbol = “$”;
}
34
Unnecessary abstraction
The smell occurs when an abstraction gets introduced in a software
design which is actually not needed and thus could have been avoided.
35
36
The principle of encapsulation
37
Enabling techniques for encapsulation
38
39
40
Leaky encapsulation
This smell arises when an abstraction “exposes” or “leaks”
implementation details through its public interface.
41
Refactoring leaky encapsulation smell
42
43
44
Missing encapsulation
This smell occurs when the encapsulation of implementation
variations in a type or hierarchy is missing.
45
Refactoring missing encapsulation smell
46
Refactoring missing encapsulation smell
47
48
The principle of modularization
49
Enabling techniques for modularization
50
51
52
Insufficient modularization
This smell arises when an existing abstraction could be further
decomposed thereby reducing its interface size, implementation
complexity or both. Two variants: a) When an abstraction has a large number of members in its interface, its
implementation, or both
b) When an abstraction has one or more methods with excessive complexity
53
Insufficient modularization – Example
The abstract class java.awt.Component is
an example of insufficient modularization
It is a massive class with 332 methods
(of which 259 are public!)
11 nested/inner classes
107 fields (including constants)
source file spans 10,102 lines of
code!
The Component serves as a base class
and the hierarchy is deep
Derived classes inherit the members
=> life is quite difficult!
54
55
56
57
Cyclically-dependent modularization
This smell arises when two or more class-level abstractions depend
on each other directly or indirectly (creating a tight coupling among
the abstractions). (This smell is commonly known as “cyclic dependencies”)
58
Refactoring cyclically-dependent modularization
59
Refactoring cyclically-dependent modularization
60
Refactoring cyclically-dependent modularization
61
Refactoring cyclically-dependent modularization
62
Refactoring cyclically-dependent modularization
63
Refactoring cyclically-dependent modularization
64
65
The principle of hierarchy
66
Enabling techniques for hierarchy
67
68
69
Unfactored hierarchy
This smell arises when the types in a hierarchy share unnecessary
duplication in the hierarchy. Two forms of this smell:
• Duplication in sibling types
• Duplication in super and subtypes
70
A refactoring for missing intermediate types
71
Refactoring for unfactored hierarchy
72
Refactoring for unfactored hierarchy
73
74
75
76
Broken hierarchy
This smell arises when the base abstraction and its derived
abstraction(s) conceptually do not share “IS-A” relationship
(resulting in broken substitutability).
This design smell arises when inheritance is used wrongly instead of
using composition.
77
LSP
It should be possible to replace objects of supertype with
objects of subtypes without altering the desired behavior of
the program
78
Refactoring broken hierarchy
79
Refactoring broken hierarchy
80
81
82
Unnecessary hierarchy
This smell arises when an inheritance hierarchy has one or more unnecessary
abstractions. Includes the following cases:
• all the subtypes are unnecessary (i.e., inappropriate use of inheritance)
• supertype has only one subtype (i.e., speculative generalization)
• intermediate types are unnecessary
83
Refactoring unnecessary hierarchy
84
Refactoring unnecessary hierarchy
85
Refactoring unnecessary hierarchy
86
Summary till now
Abstraction SmellsIncomplete Abstraction
Duplicate Abstraction
Unnecessary Abstraction
Encapsulation Smells Leaky Encapsulation
Missing Encapsulation
Modularization SmellsInsufficient Modularization
Cyclically-dependent Modularization
Hierarchy SmellsUnfactored Hierarchy
Broken Hierarchy
Unnecessary Hierarchy
87
Outline
Introduction – Design Quality, Technical Debt, and Design Smells
Design Smells Catalog – Examples and corresponding Refactoring
The Smell Ecosystem and Repaying Technical Debt in Practice
88
Smell Ecosystem
DD
DD
DD
DD
DD
SmellSmell
Smell
DD
DD: Design DecisionDesign
89
Role of context in smells and refactoring
Could it be Duplicate Abstraction, Unfactored
Hierarchy, or Unnecessary Abstraction smell?
90
Interplay of Smells: Co-occurring smells
91
Interplay of Smells: Amplification
Insufficient Modularization smell due to Component
class amplify the impact of deep hierarchy negatively.
92
Interplay of Smells: Deeper problems
93
How to improve design quality in practice?
94
Refactoring process model
95
What were your key takeaways?
96
Our upcoming book on this topic!
97
98
References
99
Ganesh Samarthyam
Twitter@GSamarthyam
Girish Suryanarayana
Twitter@girish_sur
Tushar Sharma
Twitter@Sharma__Tushar