172
Girish Suryanarayana, Tushar Sharma, Ganesh Samarthyam

Refactoring for Software Design Smells - 1 day Workshop

Embed Size (px)

Citation preview

Page 1: Refactoring for Software Design Smells - 1 day Workshop

Girish Suryanarayana, Tushar Sharma, Ganesh Samarthyam

Page 2: Refactoring for Software Design Smells - 1 day Workshop

2

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 3: Refactoring for Software Design Smells - 1 day Workshop

3

Why care about software quality?

Poor software quality

costs more than $150 billion

per annum in U.S.

and greater than $500 billion

per annum worldwide

- Capers Jones

Page 4: Refactoring for Software Design Smells - 1 day Workshop

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!

Page 5: Refactoring for Software Design Smells - 1 day Workshop

5

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, …

Page 6: Refactoring for Software Design Smells - 1 day Workshop

6

Technical debt

“Technical debt is the debt that accrues

when you knowingly or unknowingly make

wrong or non-optimal design decisions”

Reference: Refatoring for Software Design Smells– Girish et al Morgan Kaufman 2014

Page 7: Refactoring for Software Design Smells - 1 day Workshop

7

Why care about technical debt?

Global 'IT Debt' as $500 billion

for the year 2010, with

potential to grow to $1 trillion

by 2015

- Gartner

Page 8: Refactoring for Software Design Smells - 1 day Workshop

8

Why care about technical debt?

Reference: Zen and the art of software quality – Jim Highsmith Agile 2009 conference

Page 9: Refactoring for Software Design Smells - 1 day Workshop

9

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

Page 10: Refactoring for Software Design Smells - 1 day Workshop

10

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 11: Refactoring for Software Design Smells - 1 day Workshop

11

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

Page 12: Refactoring for Software Design Smells - 1 day Workshop

12

Why care about refactoring?

As an evolving program is

continually changed, its

complexity, reflecting

deteriorating structure,

increases unless work is done

to maintain or reduce it

- Lehman's law of Increasing

Complexity

Page 13: Refactoring for Software Design Smells - 1 day Workshop

13

What are design smells?

“Design smells are certain structures in the

design that indicate

violation of fundamental design principles

and

negatively impact design quality”

Reference: Refatoring for Software Design Smells– Girish et al Morgan Kaufman 2014

Page 14: Refactoring for Software Design Smells - 1 day Workshop

14

What is design quality?

Quality

Attribute Definition

Understandability The ease with which the design fragment can be comprehended.

Changeability The ease with which a design fragment can be modified (without causing

ripple effects) when an existing functionality is changed.

Extensibility The ease with which a design fragment can be enhanced or extended (without

ripple effects) for supporting new functionality.

Reusability The ease with which a design fragment can be used in a problem context other

than the one for which the design fragment was originally developed.

Testability The ease with which a design fragment supports the detection of defects

within it via testing.

Reliability

The extent to which the design fragment supports the correct realization of

the functionality and helps guard against the introduction of runtime

problems.

Page 15: Refactoring for Software Design Smells - 1 day Workshop

“Design smells” aka…

Page 16: Refactoring for Software Design Smells - 1 day Workshop

16

So, what causes design smells?

Page 17: Refactoring for Software Design Smells - 1 day Workshop

17

Most common cause of design smells

Page 18: Refactoring for Software Design Smells - 1 day Workshop

18

Another cause: not adhering to processes

Page 19: Refactoring for Software Design Smells - 1 day Workshop

19

Why should 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

Page 20: Refactoring for Software Design Smells - 1 day Workshop

20

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

Page 21: Refactoring for Software Design Smells - 1 day Workshop

21

Design principles used to classify design smells

Des

ign

Pri

nci

ple

s

Abstraction

Encapsulation

Modularization

Hierarchy

Page 22: Refactoring for Software Design Smells - 1 day Workshop

22

Design principles and enabling techniques

PHAME: Principles of Hierarchy, Abstraction, Modularization and Encapsulation

Page 23: Refactoring for Software Design Smells - 1 day Workshop

23

What is refactoring?

Refactoring (noun): a change

made to the internal structure of

software to make it easier to

understand and cheaper to

modify without changing its

observable behavior

Refactor (verb): to restructure

software by applying a series

of refactorings without

changing its observable

behavior

Page 24: Refactoring for Software Design Smells - 1 day Workshop

24

A note on examples in this presentation

Almost all examples are from real-world software

Most examples are from OpenJDK 7.0 (open source)

Examples from industrial software are “sanitized” – they do not reveal

anything about where they came from…

All illustrations are mostly as UML diagrams so no need to know Java

Though you’ll appreciate them more if you are from a Java background

A few code examples are in Java, because JAVA is the most widely

used language They are simple enough for people of any programming background to

understand

Page 25: Refactoring for Software Design Smells - 1 day Workshop

25

Scope/Focus: Only structural design smells

Page 26: Refactoring for Software Design Smells - 1 day Workshop

26

Page 27: Refactoring for Software Design Smells - 1 day Workshop

27

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 28: Refactoring for Software Design Smells - 1 day Workshop

28

The principle of abstraction

“The principle of abstraction advocates the simplification of entities

through reduction and generalization: reduction is by elimination of

unnecessary details and generalization is by identification and

specification of common and important characteristics”

Page 29: Refactoring for Software Design Smells - 1 day Workshop

29

Enabling techniques for abstraction

Page 30: Refactoring for Software Design Smells - 1 day Workshop

30

public class Throwable {

// following method is available from Java 1.0 version.

// Prints the stack trace as a string to standard output

// for processing a stack trace,

// we need to write regular expressions

public void printStackTrace();

// other methods omitted

}

Page 31: Refactoring for Software Design Smells - 1 day Workshop

31

Missing abstraction

This smell arises when clumps of data or encoded strings are used

instead of creating a class or an interface.

Page 32: Refactoring for Software Design Smells - 1 day Workshop

32

Refactoring for missing abstraction smell public class Throwable {

// following method is available from Java 1.0 version.

// Prints the stack trace as a string to standard output

// for processing a stack trace,

// we need to write regular expressions

public void printStackTrace();

// other methods omitted

}

public class Throwable {

public void printStackTrace();

public StackTraceElement[] getStackTrace(); // Since 1.4

// other methods omitted

}

public final class StackTraceElement {

public String getFileName();

public int getLineNumber();

public String getClassName();

public String getMethodName();

public boolean isNativeMethod();

}

Page 33: Refactoring for Software Design Smells - 1 day Workshop

33

Page 34: Refactoring for Software Design Smells - 1 day Workshop

34

Imperative abstraction

This smell arises when an operation is turned into a class.

This smell manifests as a class that has only one method defined

within the class. At times, the class name itself may be identical to

the one method defined within it.

Page 35: Refactoring for Software Design Smells - 1 day Workshop

35

Refactoring imperative abstraction smell

Page 36: Refactoring for Software Design Smells - 1 day Workshop

36

Page 37: Refactoring for Software Design Smells - 1 day Workshop

37

Incomplete abstraction

• This smell arises when a type does not support a responsibility completely

• Specifically, the public interface of the type is incomplete in that it does not

support all behavior needed by objects of its type

Page 38: Refactoring for Software Design Smells - 1 day Workshop

38

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!

Page 39: Refactoring for Software Design Smells - 1 day Workshop

39

Another example

Page 40: Refactoring for Software Design Smells - 1 day Workshop

40

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

Page 41: Refactoring for Software Design Smells - 1 day Workshop

41

The Abstract Factory pattern

Page 42: Refactoring for Software Design Smells - 1 day Workshop

42

java.util.Calendar

In addition to methods supporting dates, the class has methods for supporting

time as well!

Page 43: Refactoring for Software Design Smells - 1 day Workshop

43

Multi-faceted abstraction

This smell arises when an abstraction has more than one

responsibility assigned to it.

Page 44: Refactoring for Software Design Smells - 1 day Workshop

44

Refactoring for multifaceted abstraction smell

Page 45: Refactoring for Software Design Smells - 1 day Workshop

45

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; // '#'

}

Page 46: Refactoring for Software Design Smells - 1 day Workshop

46

class Currency { public static String DOLLAR = "\u0024"; public static String EURO = "\u20AC"; public static String RUPEE = "\u20B9"; public static String YEN = "\u00A5"; // no other members in this class }

Page 47: Refactoring for Software Design Smells - 1 day Workshop

47

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.

Page 48: Refactoring for Software Design Smells - 1 day Workshop

48

Unused abstract classes in an application

Page 49: Refactoring for Software Design Smells - 1 day Workshop

49

Unutilized abstraction

This smell arises when an abstraction is left unused (either not

directly used or not reachable).

Two forms:

• Unreferenced abstractions – Concrete classes that are not

being used by anyone

• Orphan abstractions – Stand-alone interfaces/abstract classes

that do not have any derived abstractions

Page 50: Refactoring for Software Design Smells - 1 day Workshop

50

Refactoring for unutilized abstraction

Page 51: Refactoring for Software Design Smells - 1 day Workshop

51

Page 52: Refactoring for Software Design Smells - 1 day Workshop

52

• executing objects of type ActionEvent at specified intervals

javax.swing.Timer

• scheduling a thread to execute in the future as a background thread

java.util.Timer

• sending out an alarm to wake-up the listeners that have registered to get timer notifications

javax.management.timer.Timer

Page 53: Refactoring for Software Design Smells - 1 day Workshop

53

/*

* Note on casts to double below. If the arithmetic of

* x+w or y+h is done in float, then some bits may be

* lost if the binary exponents of x/y and w/h are not

* similar. By converting to double before the addition

* we force the addition to be carried out in double to

* avoid rounding error in the comparison.

*

* See bug 4320890 for problems that this inaccuracy causes.

*/

/*

* Note on casts to double below. If the arithmetic of

* x+w or y+h is done in int, then we may get integer

* overflow. By converting to double before the addition

* we force the addition to be carried out in double to

* avoid overflow in the comparison.

*

* See bug 4320890 for problems that this can cause.

*/

Rectangle2D class Rectangle class

Page 54: Refactoring for Software Design Smells - 1 day Workshop

54

Duplicate abstraction

This smell arises when two or more abstractions have identical

names or identical implementation or both.

Page 55: Refactoring for Software Design Smells - 1 day Workshop

55

Page 56: Refactoring for Software Design Smells - 1 day Workshop

56

Types 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

Page 57: Refactoring for Software Design Smells - 1 day Workshop

57

Refactoring for Date example

Page 58: Refactoring for Software Design Smells - 1 day Workshop

58

Sum

mar

y o

f Sm

ells

Vio

lati

ng

Ab

stra

ctio

n

Page 59: Refactoring for Software Design Smells - 1 day Workshop

59

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 60: Refactoring for Software Design Smells - 1 day Workshop

60

The principle of encapsulation

“The principle of encapsulation advocates separation of concerns and

information hiding through techniques such as hiding implementation

details of abstractions and hiding variations”

Page 61: Refactoring for Software Design Smells - 1 day Workshop

61

Enabling techniques for encapsulation

Page 62: Refactoring for Software Design Smells - 1 day Workshop

62

Page 63: Refactoring for Software Design Smells - 1 day Workshop

63

Lenient encapsulation

This design smell arises when the hiding is deficient so that clients

can access the implementation aspects of the abstraction directly

(An abstraction should expose only the interface to the clients

and hide the implementation details.)

Page 64: Refactoring for Software Design Smells - 1 day Workshop

64

Lenient encapsulation – Example

The java.awt.Rectangle class has 4

pubic fields: x, y, width, and height

in addition to public getter and

setter methods for these fields!

Smell since the accessibility of

its members is more permissive

(i.e., are declared public) than

actually required (i.e., they are

required to be declared private)

Refactoring suggestion: Make all

data members private

Lenient encapsulation

Insufficient modularization

Page 65: Refactoring for Software Design Smells - 1 day Workshop

65

Page 66: Refactoring for Software Design Smells - 1 day Workshop

66

Case study: Use of global variable “current” in Linux

Page 67: Refactoring for Software Design Smells - 1 day Workshop

67

Page 68: Refactoring for Software Design Smells - 1 day Workshop

68

Page 69: Refactoring for Software Design Smells - 1 day Workshop

69

Leaky encapsulation

This smell arises when an abstraction “exposes” or “leaks”

implementation details through its public interface.

Page 70: Refactoring for Software Design Smells - 1 day Workshop

70

Refactoring leaky encapsulation smell

Page 71: Refactoring for Software Design Smells - 1 day Workshop

71

Page 72: Refactoring for Software Design Smells - 1 day Workshop

72

Page 73: Refactoring for Software Design Smells - 1 day Workshop

73

Missing encapsulation

This smell occurs when the encapsulation of implementation

variations in a type or hierarchy is missing.

Page 74: Refactoring for Software Design Smells - 1 day Workshop

74

How about this refactoring?

Page 75: Refactoring for Software Design Smells - 1 day Workshop

75

Refactoring missing encapsulation smell

Page 76: Refactoring for Software Design Smells - 1 day Workshop

76

Refactoring missing encapsulation smell

Page 77: Refactoring for Software Design Smells - 1 day Workshop

77

switch (transferType) {

case DataBuffer.TYPE_BYTE:

byte bdata[] = (byte[])inData;

pixel = bdata[0] & 0xff;

length = bdata.length;

break;

case DataBuffer.TYPE_USHORT:

short sdata[] = (short[])inData;

pixel = sdata[0] & 0xffff;

length = sdata.length;

break;

case DataBuffer.TYPE_INT:

int idata[] = (int[])inData;

pixel = idata[0];

length = idata.length;

break;

default:

throw new UnsupportedOperationException("This method has not been "+ "implemented

for transferType " + transferType);

}

Page 78: Refactoring for Software Design Smells - 1 day Workshop

78

Unexploited encapsulation

This smell arises when client code uses explicit type checks (using

chained if-else or switch statements that check for the type of the

object) instead of exploiting the variation in types already

encapsulated within a hierarchy.

Page 79: Refactoring for Software Design Smells - 1 day Workshop

79

Refactoring unexploited encapsulation smell

protected int transferType; protected DataBuffer dataBuffer;

pixel = dataBuffer.getPixel();

length = dataBuffer.getSize();

switch (transferType) {

case DataBuffer.TYPE_BYTE:

byte bdata[] = (byte[])inData;

pixel = bdata[0] & 0xff;

length = bdata.length;

break;

case DataBuffer.TYPE_USHORT:

short sdata[] = (short[])inData;

pixel = sdata[0] & 0xffff;

length = sdata.length;

break;

case DataBuffer.TYPE_INT:

int idata[] = (int[])inData;

pixel = idata[0];

length = idata.length;

break;

default:

throw new UnsupportedOperationException("This method

has not been "+ "implemented for transferType " +

transferType);

}

Page 80: Refactoring for Software Design Smells - 1 day Workshop

80

Summary of Smells Violating Encapsulation

Page 81: Refactoring for Software Design Smells - 1 day Workshop

81

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 82: Refactoring for Software Design Smells - 1 day Workshop

82

The principle of modularization

“The principle of modularization advocates the creation of

cohesive and loosely coupled abstractions through

techniques such as localization and decomposition”

Page 83: Refactoring for Software Design Smells - 1 day Workshop

83

Enabling techniques for modularization

Page 84: Refactoring for Software Design Smells - 1 day Workshop

84

Page 85: Refactoring for Software Design Smells - 1 day Workshop

85

Broken modularization

This smell arises when members of an abstraction are broken and

spread across multiple abstractions (when ideally they should

have been localized into a single abstraction).

Two forms of this smell:

• Data and methods that ideally belong to an abstraction are

split among two or more abstractions.

• Methods that ideally belong to abstraction are split among

two or more abstractions.

Page 86: Refactoring for Software Design Smells - 1 day Workshop

86

Suggested refactoring for broken modularization

Page 87: Refactoring for Software Design Smells - 1 day Workshop

87

Refactoring for broken modularization smell

Page 88: Refactoring for Software Design Smells - 1 day Workshop

88

Page 89: Refactoring for Software Design Smells - 1 day Workshop

89

Page 90: Refactoring for Software Design Smells - 1 day Workshop

90

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

Page 91: Refactoring for Software Design Smells - 1 day Workshop

91

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!

Page 92: Refactoring for Software Design Smells - 1 day Workshop

92

Page 93: Refactoring for Software Design Smells - 1 day Workshop

93

Page 94: Refactoring for Software Design Smells - 1 day Workshop

94

Page 95: Refactoring for Software Design Smells - 1 day Workshop

95

Page 96: Refactoring for Software Design Smells - 1 day Workshop

96

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

Page 97: Refactoring for Software Design Smells - 1 day Workshop

97

Refactoring cyclically-dependent modularization

Page 98: Refactoring for Software Design Smells - 1 day Workshop

98

Refactoring cyclically-dependent modularization

Page 99: Refactoring for Software Design Smells - 1 day Workshop

99

Refactoring cyclically-dependent modularization

Page 100: Refactoring for Software Design Smells - 1 day Workshop

100

Refactoring cyclically-dependent modularization

Page 101: Refactoring for Software Design Smells - 1 day Workshop

101

Refactoring cyclically-dependent modularization

Page 102: Refactoring for Software Design Smells - 1 day Workshop

102

Refactoring cyclically-dependent modularization

Page 103: Refactoring for Software Design Smells - 1 day Workshop

103

Refactoring cyclically-dependent modularization

Page 104: Refactoring for Software Design Smells - 1 day Workshop

104

Practical consideration: unit cycles

Page 105: Refactoring for Software Design Smells - 1 day Workshop

105

Page 106: Refactoring for Software Design Smells - 1 day Workshop

106

Page 107: Refactoring for Software Design Smells - 1 day Workshop

107

Hub-like modularization

This smell arises when a class-level abstraction has dependencies

with large number of other class-level abstractions (high incoming

as well as outgoing dependencies).

Page 108: Refactoring for Software Design Smells - 1 day Workshop

108

Summary of Smells Violating Modularization

Page 109: Refactoring for Software Design Smells - 1 day Workshop

109

Outline

Introduction

Design smells

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring Process and

Tools

Page 110: Refactoring for Software Design Smells - 1 day Workshop

110

The principle of hierarchy

“The principle of hierarchy advocates the creation of a

hierarchical organization of abstractions using techniques such

as classification, generalization, substitutability, and ordering”

Page 111: Refactoring for Software Design Smells - 1 day Workshop

111

Enabling techniques for hierarchy

Page 112: Refactoring for Software Design Smells - 1 day Workshop

112

Page 113: Refactoring for Software Design Smells - 1 day Workshop

113

Page 114: Refactoring for Software Design Smells - 1 day Workshop

114

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

Page 115: Refactoring for Software Design Smells - 1 day Workshop

115

A refactoring for missing intermediate types

Page 116: Refactoring for Software Design Smells - 1 day Workshop

116

Refactoring for unfactored hierarchy

Page 117: Refactoring for Software Design Smells - 1 day Workshop

117

Refactoring for unfactored hierarchy

Page 118: Refactoring for Software Design Smells - 1 day Workshop

118

public Insets getBorderInsets(Component c, Insets insets){

Insets margin = null;

// Ideally we'd have an interface defined for classes which

// support margins (to avoid this hackery), but we've

// decided against it for simplicity

//

if (c instanceof AbstractButton) {

margin = ((AbstractButton)c).getMargin();

} else if (c instanceof JToolBar) {

margin = ((JToolBar)c).getMargin();

} else if (c instanceof JTextComponent) {

margin = ((JTextComponent)c).getMargin();

}

// rest of the code omitted …

Page 119: Refactoring for Software Design Smells - 1 day Workshop

119

Missing hierarchy

This smell arises when an abstraction uses conditional logic to

determine behavior where a hierarchy could have been formed to

exploit variation in behavior.

Page 120: Refactoring for Software Design Smells - 1 day Workshop

120

Refactoring for missing hierarchy

Page 121: Refactoring for Software Design Smells - 1 day Workshop

121

Refactoring for missing hierarchy

margin = c.getMargin();

if (c instanceof AbstractButton) {

margin = ((AbstractButton)c).getMargin();

} else if (c instanceof JToolBar) {

margin = ((JToolBar)c).getMargin();

} else if (c instanceof JTextComponent) {

margin = ((JTextComponent)c).getMargin();

}

Page 122: Refactoring for Software Design Smells - 1 day Workshop

122

Page 123: Refactoring for Software Design Smells - 1 day Workshop

123

Page 124: Refactoring for Software Design Smells - 1 day Workshop

124

Deep hierarchy

This smell arises when an inheritance hierarchy is excessively deep.

Page 125: Refactoring for Software Design Smells - 1 day Workshop

125

Refactoring for deep hierarchy

Page 126: Refactoring for Software Design Smells - 1 day Workshop

126

Refactoring for deep hierarchy

/**

* Pluggable look and feel interface for JButton.

*/

public abstract class ButtonUI extends ComponentUI {

}

Page 127: Refactoring for Software Design Smells - 1 day Workshop

127

Page 128: Refactoring for Software Design Smells - 1 day Workshop

128

Wide hierarchy

This smell arises when an inheritance hierarchy is “too” wide and

shallow indicating missing intermediate abstractions.

Page 129: Refactoring for Software Design Smells - 1 day Workshop

129

Suggested refactoring for wide hierarchy

Page 130: Refactoring for Software Design Smells - 1 day Workshop

130

Page 131: Refactoring for Software Design Smells - 1 day Workshop

131

Rebellious hierarchy

This smell arises when a subtype rejects the methods

provided by its supertype(s).

Page 132: Refactoring for Software Design Smells - 1 day Workshop

132

How about this refactoring for rebellious hierarchy?

Page 133: Refactoring for Software Design Smells - 1 day Workshop

133

How about this refactoring for rebellious hierarchy?

Page 134: Refactoring for Software Design Smells - 1 day Workshop

134

How about this refactoring for rebellious hierarchy?

Page 135: Refactoring for Software Design Smells - 1 day Workshop

135

Dealing with addComponent() in Composite pattern

Page 136: Refactoring for Software Design Smells - 1 day Workshop

136

Page 137: Refactoring for Software Design Smells - 1 day Workshop

137

Page 138: Refactoring for Software Design Smells - 1 day Workshop

138

Page 139: Refactoring for Software Design Smells - 1 day Workshop

139

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.

Page 140: Refactoring for Software Design Smells - 1 day Workshop

140

Liskov’s Substitution Principle (LSP)

It should be possible to replace objects of supertype with

objects of subtypes without altering the desired behavior of

the program

Barbara Liskov

Page 141: Refactoring for Software Design Smells - 1 day Workshop

141

Refactoring broken hierarchy

Page 142: Refactoring for Software Design Smells - 1 day Workshop

142

Refactoring broken hierarchy

Page 143: Refactoring for Software Design Smells - 1 day Workshop

143

Page 144: Refactoring for Software Design Smells - 1 day Workshop

144

Multipath hierarchy

This smell arises when a subtype inherits both directly

as well as indirectly from a supertype leading to

unnecessary inheritance paths in the hierarchy.

Page 145: Refactoring for Software Design Smells - 1 day Workshop

145

Suggested refactoring for multipath hierarchy

Page 146: Refactoring for Software Design Smells - 1 day Workshop

146

How about multiple interface inheritance?

Page 147: Refactoring for Software Design Smells - 1 day Workshop

147

Real-world example

Page 148: Refactoring for Software Design Smells - 1 day Workshop

148

Page 149: Refactoring for Software Design Smells - 1 day Workshop

149

Page 150: Refactoring for Software Design Smells - 1 day Workshop

150

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

Page 151: Refactoring for Software Design Smells - 1 day Workshop

151

Refactoring unnecessary hierarchy

Page 152: Refactoring for Software Design Smells - 1 day Workshop

152

Refactoring unnecessary hierarchy

Page 153: Refactoring for Software Design Smells - 1 day Workshop

153

Refactoring unnecessary hierarchy

Page 154: Refactoring for Software Design Smells - 1 day Workshop

154

Refactoring unnecessary hierarchy

Page 155: Refactoring for Software Design Smells - 1 day Workshop

155

Practical considerations: language limitations

Page 156: Refactoring for Software Design Smells - 1 day Workshop

156

Page 157: Refactoring for Software Design Smells - 1 day Workshop

157

Speculative hierarchy

This smell arises when one or more types in a hierarchy are provided speculatively

(i.e., based on imagined needs rather than real requirements)

Page 158: Refactoring for Software Design Smells - 1 day Workshop

158

Refactoring for speculative hierarchy

Page 159: Refactoring for Software Design Smells - 1 day Workshop

159

Page 160: Refactoring for Software Design Smells - 1 day Workshop

160

Cyclic hierarchy

This smell arises when a supertype in a hierarchy

depends on any of its subtypes.

Page 161: Refactoring for Software Design Smells - 1 day Workshop

161

Suggested refactoring for cyclic hierarchy

Page 162: Refactoring for Software Design Smells - 1 day Workshop

162

Sum

mar

y o

f Sm

ells

Vio

lati

ng

Hie

rarc

hy

Page 163: Refactoring for Software Design Smells - 1 day Workshop

163

How to improve design quality in practice?

Page 164: Refactoring for Software Design Smells - 1 day Workshop

164

Refactoring process model

Page 165: Refactoring for Software Design Smells - 1 day Workshop

165

Suggested Reading

Page 166: Refactoring for Software Design Smells - 1 day Workshop

166

More on design smells?

Page 167: Refactoring for Software Design Smells - 1 day Workshop

167

Key take-aways

Technical debt accrues when you knowingly or unknowingly make wrong or non-optimal design decisions

Design smells indicate violation of fundamental design principles

Also, design smells negatively impact design quality

We need to care about technical debt

Accumulating debt will lead to “technical bankruptcy”

Refactoring is the primary means to repay technical debt

Page 168: Refactoring for Software Design Smells - 1 day Workshop

168

Key take-aways

Apply fundamental design principles (such as abstraction, encapsulation, modularization, and hierarchy) to create high-quality software

Smells are related: they tend to co-occur, amplify the effect of other smells, or can indicate deeper design problems

Use the IMPaCT process model to identify/mark, prioritize, and refactor design smells in practice

Page 169: Refactoring for Software Design Smells - 1 day Workshop

169

Design principles and enabling techniques

Page 170: Refactoring for Software Design Smells - 1 day Workshop

170

Page 171: Refactoring for Software Design Smells - 1 day Workshop

171

Thank you!

Page 172: Refactoring for Software Design Smells - 1 day Workshop

Girish Suryanarayana, Tushar Sharma, Ganesh Samarthyam