0% found this document useful (0 votes)
37 views148 pages

Refactoring For DesignSmells 2021

The document discusses design smells, which are structures in software design that violate fundamental design principles and negatively impact quality. Up to 64% of software defects can be traced back to errors in design. Design quality is important because it impacts maintainability, reliability, and other quality attributes. Design smells are indicators of deeper quality issues like rigidity, opacity, and unnecessary complexity. The document outlines some common causes of design smells, such as changing requirements, tight deadlines, lack of design skills or adherence to design processes, and over-engineering. Addressing design smells is important for software quality and changeability.

Uploaded by

uttamtoday
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views148 pages

Refactoring For DesignSmells 2021

The document discusses design smells, which are structures in software design that violate fundamental design principles and negatively impact quality. Up to 64% of software defects can be traced back to errors in design. Design quality is important because it impacts maintainability, reliability, and other quality attributes. Design smells are indicators of deeper quality issues like rigidity, opacity, and unnecessary complexity. The document outlines some common causes of design smells, such as changing requirements, tight deadlines, lack of design skills or adherence to design processes, and over-engineering. Addressing design smells is important for software quality and changeability.

Uploaded by

uttamtoday
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 148

Refactoring for Design Smells

Restricted © Siemens AG 2018 Siemens Corporate Technology


Outline

Introduction

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring design smells in practice

Restricted © Siemens AG 2018


Page 2 04.06.2018 Slide 2 CT RDA SSI RSE-IN
Capers Jones on design errors in industrial software

Industry Data on Defect Origins


120

100
Percentage Contribution

80
Adminstrative Errors
Documentation Errors
60
Bad Fixes
Coding Errors
40 Design Errors
Requirements Errors
20

0
IBM SPR TRW MITRE Nippon Electric
Corportation Corporation Corporation Corporation Corp
(MVS) (Client Studies)

* http://sqgne.org/presentations/2012-13/Jones-Sep-2012.pdf Up to 64% of software


defects can be traced back to
Restricted © Siemens AG 2018 errors in software design in
enterprise software!
Page 3 04.06.2018 CT RDA SSI RSE-IN
Why care about design quality?

Software Technical
Quality Debt

Poor software quality The debt that accrues when


costs more than $150 you knowingly or
billion per year in U.S. and
Design unknowingly make wrong or
greater than $500 billion Quality non-optimal design decisions
per year worldwide

Design Quality means


changeability, extensibility,
understandability, reusability,
Restricted © Siemens AG 2018 ...
Page 4 04.06.2018 CT RDA SSI RSE-IN
Why care about technical debt?

Restricted © Siemens AG 2018


Page 5 04.06.2018 Slide 5 CT RDA SSI RSE-IN
Technical Bankruptcy!!

Restricted © Siemens AG 2018


Page 6 04.06.2018 Slide 6 CT RDA SSI RSE-IN
What constitutes technical debt?

Documentatio
Code debt Design debt Test debt
n debt

No
Static analysis Lack of tests documentation

Design smells
tool violations for important
concerns

Inconsistent Violations of Inadequate Outdated


coding style design rules test coverage documentation

Restricted © Siemens AG 2018


Page 7 04.06.2018 Slide 7 CT RDA SSI RSE-IN
“Design smells” aka…
What is a smell?

“Design smells are certain structures in the design that indicate violation
of fundamental design principles and negatively impact design quality.”

Restricted © Siemens AG 2018


Page 8 04.06.2018 CT RDA SSI RSE-IN
Why care about smells?
Indicators
▪ Rigidity & Fragility
▪ Immobility & Opacity
▪ Needless complexity
Design ▪ Needless repetition
Smells ▪ …

Impacted Quality
Desig
▪ Reusability
n
▪ Changeability Qualit
▪ Understandability y
Product Impacted Quality
▪ Extensibility
Quality ▪ Reliability: Impacted by
▪ …
poor understandability
▪ Performance: Impacted
by high complexity
▪ Maintainability: Affected
by changeability &
Restricted © Siemens AG 2018
extensibility
Page 9 04.06.2018 Slide 9 ▪ … CT RDA SSI RSE-IN
What causes design smells?

Restricted © Siemens AG 2018


Page 10 04.06.2018 Slide 10 CT RDA SSI RSE-IN
Most common cause of design smells

Restricted © Siemens AG 2018


Page 11 04.06.2018 Slide 11 CT RDA SSI RSE-IN
Most common cause of design smells

Restricted © Siemens AG 2018


Page 12 04.06.2018 Slide 12 CT RDA SSI RSE-IN
Another common cause

Restricted © Siemens AG 2018


Page 13 04.06.2018 Slide 13 CT RDA SSI RSE-IN
Not adhering to processes

Restricted © Siemens AG 2018


Page 14 04.06.2018 Slide 14 CT RDA SSI RSE-IN
Unable to adapt

Restricted © Siemens AG 2018


Page 15 04.06.2018 Slide 15 CT RDA SSI RSE-IN
Over-engineering

Restricted © Siemens AG 2018


Page 16 04.06.2018 Slide 16 CT RDA SSI RSE-IN
One-time Violation --> Long-term Habit

Restricted © Siemens AG 2018


Page 17 04.06.2018 Slide 17 CT RDA SSI RSE-IN
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

Restricted © Siemens AG 2018


Page 18 04.06.2018 Slide 18 CT RDA SSI RSE-IN
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

Restricted © Siemens AG 2018


Page 19 04.06.2018 Slide 19 CT RDA SSI RSE-IN
Principles used to classify design smells

• Simplify entities via


Abstraction • Reduction of unnecessary details
• Generalization of common and important aspects

• Separation of concerns and information hiding via


Encapsulation • Hiding implementation details
• Hiding variations

• Cohesive and loosely-coupled abstractions via


Modularization • Localization
• Decomposition

• Hierarchical organization of abstractions via


Hierarchy • Classification and ordering
• Generalization and factoring

Restricted © Siemens AG 2018


Page 20 04.06.2018 Slide 20 CT RDA SSI RSE-IN
Quality attributes impacted by smells

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

The ease with which a design fragment can be modified (without causing ripple
Changeability
effects) when an existing functionality is changed.

The ease with which a design fragment can be enhanced or extended (without
Extensibility
ripple effects) for supporting new functionality.

The ease with which a design fragment can be used in a problem context other
Reusability
than the one for which the design fragment was originally developed.

The ease with which a design fragment supports the detection of defects within
Testability
it via testing.

The extent to which the design fragment supports the correct realization of the
Reliability
functionality and helps guard against the introduction of runtime problems.
Restricted © Siemens AG 2018
Page 21 04.06.2018 Slide 21 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 22 04.06.2018 Slide 22 CT RDA SSI RSE-IN
A note on smells and examples in this presentation

For each smell we present


1 example
Definition of the smell
Refactoring for the smell
Practical considerations where the smell may be a conscious decision

Most examples are from OpenJDK (open source)


All illustrations are mostly as UML-like diagrams so no need to 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

Restricted © Siemens AG 2018


Page 23 04.06.2018 Slide 23 CT RDA SSI RSE-IN
Outline

Introduction

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring design smells in practice

Restricted © Siemens AG 2018


Page 24 04.06.2018 Slide 24 CT RDA SSI RSE-IN
The principle of abstraction

• Simplify entities via


Abstraction • Reduction of unnecessary details
• Generalization of common and important aspects

Restricted © Siemens AG 2018


Page 25 04.06.2018 Slide 25 CT RDA SSI RSE-IN
Enabling techniques for abstraction

Restricted © Siemens AG 2018


Page 26 04.06.2018 Slide 26 CT RDA SSI RSE-IN
<<Interface>>
Button Model
+setGroup(ButtonGroup)
… other methods

DefaultButton Model
+getGroup():ButtonGroup
… other methods

Restricted © Siemens AG 2018


Page 27 04.06.2018 Slide 27 CT RDA SSI RSE-IN
Incomplete Abstraction

This smell arises when an abstraction does not support complementary


or interrelated methods completely
Specifically, the public interface of the type is incomplete in that it
does not support all related behavior needed by objects of its type

Imagine a car
with an
accelerator but
without a brake!

Restricted © Siemens AG 2018


Page 28 04.06.2018 Slide 28 CT RDA SSI RSE-IN
Incomplete Abstraction – Example
In this case, the ButtonModel interface
<<Interface>> supports only setGroup() but no
corresponding getGroup() (which is provided
Button Model in its derived class!)
+setGroup(ButtonGroup)
Hence, ButtonModel suffers from
Incomplete Abstraction smell

How to fix it?


“Ensure coherence and completeness”
DefaultButton Model
Provide all the necessary and relevant
methods required for satisfying a
+getGroup():ButtonGroup responsibility completely in the class itself
In case of public APIs (as in this case), it
is often “too late” to fix it!
Restricted © Siemens AG 2018
Page 29 04.06.2018 Slide 29 CT RDA SSI RSE-IN
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
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

Caution – Purposely done for e.g. read-only collection

Restricted © Siemens AG 2018


Page 30 04.06.2018 Slide 30 CT RDA SSI RSE-IN
Contains only one
method
“calculateOffset”

Contains only one


method
“saveOffset”
An image processing application, wherein, the
Application class uses the OffsetCalculator to
compute the offset between 2 images and saves it
via SaveHandler class

Restricted © Siemens AG 2018


Page 31 04.06.2018 Slide 31 CT RDA SSI RSE-IN
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.

Restricted © Siemens AG 2018


Page 32 04.06.2018 Slide 32 CT RDA SSI RSE-IN
Refactoring Imperative Abstraction smell

Map domain entities

Caution – Patterns e.g. Command and Strategy


Restricted © Siemens AG 2018
Page 33 04.06.2018 Slide 33 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 34 04.06.2018 Slide 34 CT RDA SSI RSE-IN
Scanner PublicScanner

org.eclipse.jdt.internal org.eclipse.jdt.
.compiler.parser core.compiler

About 3500 lines of code (i.e. 99% of the code) are identical
across these two classes!

Restricted © Siemens AG 2018


Page 35 04.06.2018 Slide 35 CT RDA SSI RSE-IN
Duplicate Abstraction

This smell arises when two or more abstractions have identical names or
identical implementation or both.

Restricted © Siemens AG 2018


Page 36 04.06.2018 Slide 36 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 37 04.06.2018 Slide 37 CT RDA SSI RSE-IN
Refactoring Duplicate Abstraction smell

▪ “Avoid duplication”
1. Change name of one of the
abstractions
2. Factor out the commonality into a
third abstraction which can be used
by the original abstractions
3. Remove a duplication from one of
the abstractions and make it refer
to the other abstraction for that
particular functionality

Caution – Language limitations e.g. lack of generics support for primitive


types in Java
e.g. instead of Comparator<t, t>, we have Integer.compare(int a, int b),
Restricted © Siemens AG 2018 Byte.compare(byte a, byte b) etc.
Page 38 04.06.2018 Slide 38 CT RDA SSI RSE-IN
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; // '#'
}

This class is used by Formatter class, and holds three flag values used
in format specifiers, namely, “-“, “S” and “#”. These flags are encoded
as integer values 1, 2, and 4.
Restricted © Siemens AG 2018
Page 39 04.06.2018 Slide 39 CT RDA SSI RSE-IN
Unnecessary Abstraction

The smell occurs when an abstraction which is actually not needed (and thus
could have been avoided) gets introduced in a software design

Restricted © Siemens AG 2018


Page 40 04.06.2018 Slide 40 CT RDA SSI RSE-IN
Refactoring Unnecessary Abstraction smell

▪ “Assign single or meaningful responsibility”


▪ Eliminate the “unnecessary class or interface”
▪ FormattableFlags could be made as an enumeration and used
with java.util.Formatter class which provides support for formatted
output

Caution – Delegating classes e.g. Mediator and Adapter

Restricted © Siemens AG 2018


Page 41 04.06.2018 Slide 41 CT RDA SSI RSE-IN
private String isbn;

public void foo(){

if
(isbn.substring(0,2).equals(“…
”)){…}
}
public void bar(){

if
(isbn.substring(0,2).equals(“@
@@”)){…}
}

Restricted © Siemens AG 2018


Page 42 04.06.2018 Slide 42 CT RDA SSI RSE-IN
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 not shown here
}

▪ Client programs that need programmatic access to the stack trace


elements have to write code to process the stack trace to get (by getting
System.out data), for example,
▪ the line numbers or file name or class name
▪ find if the bug is a duplicate of another already-filed bug.
Restricted © Siemens AG 2018
Page 43 04.06.2018 Slide 43 CT RDA SSI RSE-IN
Missing Abstraction

This smell arises when clumps of data or encoded strings are used
instead of creating a class or an interface.

Restricted © Siemens AG 2018


Page 44 04.06.2018 Slide 44 CT RDA SSI RSE-IN
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 elided
}

Provide crisp and conceptual


boundaries and a unique identity public final class StackTraceElement {
public String getFileName();
public class Throwable {
public int getLineNumber();
public void printStackTrace();
public String getClassName();
public StackTraceElement[] getStackTrace(); // Since
public String getMethodName();
1.4
public boolean isNativeMethod();
// other methods elided
}
}

Restricted © Siemens AG 2018 Caution – Check if there is behavior associated with data
Page 45 04.06.2018 Slide 45 CT RDA SSI RSE-IN
In addition to methods
supporting dates, Calendar
class has methods for
supporting time as well!

java.util.Calendar

Restricted © Siemens AG 2018


Page 46 04.06.2018 Slide 46 CT RDA SSI RSE-IN
Multifaceted Abstraction

This smell arises when an abstraction has more than one responsibility
assigned to it.

Restricted © Siemens AG 2018


Page 47 04.06.2018 Slide 47 CT RDA SSI RSE-IN
Refactoring for Multifaceted Abstraction smell

“Assign single and meaningful responsibility”

Caution – To reduce complexity of an already extremely-


complex design
Restricted © Siemens AG 2018
Page 48 04.06.2018 Slide 48 CT RDA SSI RSE-IN
Unused abstract
classes in an
application

Restricted © Siemens AG 2018


Page 49 04.06.2018 Slide 49 CT RDA SSI RSE-IN
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

Restricted © Siemens AG 2018


Page 50 04.06.2018 Slide 50 CT RDA SSI RSE-IN
Refactoring Unutilized Abstraction smell

▪ “Assign single and meaningful responsibility”


▪ Remove the “unutilized class or interface” especially if it has been
created for an imagined need (i.e. speculatively)

Caution – Class libraries and frameworks usually provide


extension points in the form of abstract classes or interfaces and
may appear to be unused within the library or framework

Restricted © Siemens AG 2018


Page 51 04.06.2018 Slide 51 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 52 04.06.2018 Slide 52 CT RDA SSI RSE-IN
Outline

Introduction

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring design smells in practice

Restricted © Siemens AG 2018


Page 53 04.06.2018 Slide 53 CT RDA SSI RSE-IN
The principle of encapsulation

• Separation of concerns and information hiding via


Encapsulation • Hiding implementation details
• Hiding variations

Restricted © Siemens AG 2018


Page 54 04.06.2018 Slide 54 CT RDA SSI RSE-IN
Enabling techniques for encapsulation

Restricted © Siemens AG 2018


Page 55 04.06.2018 Slide 55 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 56 04.06.2018 Slide 56 CT RDA SSI RSE-IN
Deficient Encapsulation

This design smell occurs when the declared accessibility of one or more
members of a class is more permissive than actually required.
(An abstraction should expose only the interface to the clients and hide
the implementation details.)

Restricted © Siemens AG 2018


Page 57 04.06.2018 Slide 57 CT RDA SSI RSE-IN
Deficient Encapsulation – Example & Refactoring

The java.awt.Rectangle class has 4 public


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
Restricted © Siemens AG 2018 modularization
Page 58 04.06.2018 Slide 58 CT RDA SSI RSE-IN
Deficient Encapsulation – Caution

Nested classes
non-static nested class (i.e. an inner class) has access to all the
members (including private members) of its enclosing class

Performance reasons (depending upon the context)

Restricted © Siemens AG 2018


Page 59 04.06.2018 Slide 59 CT RDA SSI RSE-IN
What if the data structure i.e. LinkedList needs to be changed
tomorrow?
Restricted © Siemens AG 2018
Page 60 04.06.2018 Slide 60 CT RDA SSI RSE-IN
What if the sorting algorithm needs to be replaced with a
different sorting algorithm, say "quick sort", in the future?

Restricted © Siemens AG 2018


Page 61 04.06.2018 Slide 61 CT RDA SSI RSE-IN
Leaky Encapsulation
This smell arises when an abstraction “exposes” or “leaks” implementation
details through its public interface.

Restricted © Siemens AG 2018


Page 62 04.06.2018 Slide 62 CT RDA SSI RSE-IN
Refactoring Leaky Encapsulation smell

Internally, sort() method can use any sorting algorithm

Caution – Depends on the context. For e.g. in an embedded software


that processes and plays audio in a mobile device, some methods
and data structures (along with their types) that store metadata about
the audio stream (e.g., sampling rate, mono/stereo) need to be
directly exposed to the middleware client.
Restricted © Siemens AG 2018
Page 63 04.06.2018 Slide 63 CT RDA SSI RSE-IN
In the future, want to support
AES as well, so my class looks
like this now

What’s the problem with such an implementation of the


Encryption class?
Restricted © Siemens AG 2018
Page 64 04.06.2018 Slide 64 CT RDA SSI RSE-IN
Add a new type and
algorithm

Restricted © Siemens AG 2018


Page 65 04.06.2018 Slide 65 CT RDA SSI RSE-IN
Missing Encapsulation

This smell occurs when implementation variations are not


encapsulated (behind a hierarchy)

Restricted © Siemens AG 2018


Page 66 04.06.2018 Slide 66 CT RDA SSI RSE-IN
Refactoring Missing Encapsulation smell

Restricted © Siemens AG 2018


Page 67 04.06.2018 Slide 67 CT RDA SSI RSE-IN
Refactoring Missing Encapsulation smell

Caution – When you are aware that new variations will not emerge, a
refactoring may not be required. It could result in over-engineering.
Restricted © Siemens AG 2018
Page 68 04.06.2018 Slide 68 CT RDA SSI RSE-IN
switch (transferType) {
case DataBuffer.TYPE_BYTE:
byte bdata[] = (byte[])inData; Data
pixel = bdata[0] & 0xff; Buffer
length = bdata.length;
break;
case DataBuffer.TYPE_USHORT:
short sdata[] = (short[])inData;
pixel = sdata[0] & 0xffff;
length = sdata.length;
DataBuffer DataBuffer DataBuffer
break;
Byte UShort Int
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);
}

Restricted © Siemens AG 2018


Page 69 04.06.2018 Slide 69 CT RDA SSI RSE-IN
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.

Restricted © Siemens AG 2018


Page 70 04.06.2018 Slide 70 CT RDA SSI RSE-IN
Refactoring Unexploited Encapsulation smell

protected int transferType; protected DataBuffer dataBuffer;

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 = dataBuffer.getPixel();
pixel = sdata[0] & 0xffff;
length = sdata.length;
length = dataBuffer.getSize();
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 "
Restricted © Siemens AG 2018 + transferType);

Page 71 }
04.06.2018 Slide 71 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 72 04.06.2018 Slide 72 CT RDA SSI RSE-IN
Outline

Introduction

Abstraction smells

Encapsulation smells
Modularization smells

Hierarchy smells

Refactoring design smells in practice


Restricted © Siemens AG 2018
Page 73 04.06.2018 Slide 73 CT RDA SSI RSE-IN
The principle of Modularization

• Cohesive and loosely-coupled abstractions via


Modularization • Localization
• Decomposition
Restricted © Siemens AG 2018
Page 74 04.06.2018 Slide 74 CT RDA SSI RSE-IN
Enabling techniques for Modularization

Restricted © Siemens AG 2018


Page 75 04.06.2018 Slide 75 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 76 04.06.2018 Slide 76 CT RDA SSI RSE-IN
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 in a class that are interested in members of other classes.

Restricted © Siemens AG 2018


Page 77 04.06.2018 Slide 77 CT RDA SSI RSE-IN
Suggested refactoring for Broken Modularization

Restricted © Siemens AG 2018


Page 78 04.06.2018 Slide 78 CT RDA SSI RSE-IN
Refactoring for Broken Modularization smell

Caution:
DTOs
What’s the smell in our
Restricted © Siemens AG 2018 refactored solution?
Page 79 04.06.2018 Slide 79 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 80 04.06.2018 Slide 80 CT RDA SSI RSE-IN
Insufficient Modularization

This smell arises when an abstraction exists that has not been completely
decomposed and a further decomposition could reduce its size, implementation
complexity, or both.

There are two forms of this smell -


• Bloated interface
• Bloated implementation

Restricted © Siemens AG 2018


Page 81 04.06.2018 Slide 81 CT RDA SSI RSE-IN
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!

Restricted © Siemens AG 2018


Page 82 04.06.2018 Slide 82 CT RDA SSI RSE-IN
Refactoring for Insufficient Modularization

Refactoring for ‘bloated interface’


If a subset of the public interface consists of closely related (cohesive)
members, then extract that subset to a separate abstraction.
If the class interface serves multiple clients via client-specific methods,
consider applying the “Interface Segregation Principle” (ISP) to separate the
original interface into multiple client-specific interfaces.

Refactoring for ‘bloated implementation’


If the method logic is complex, introduce private helper methods that help
simplify the code in that method.
In case an abstraction has both Multifaceted Abstraction smell as well as
Insufficient Modularization smell, separate each responsibility within
separate (new or existing) abstractions.

Restricted © Siemens AG 2018


Page 83 04.06.2018 Slide 83 CT RDA SSI RSE-IN
Refactoring for Insufficient Modularization

The abstract class Component provides


default functionality to create
lightweight components that can be
defined by extending the Component
class.
It covers a number of concerns such as
event listening, component layout and
positioning, focus, fonts, and graphics
configuration which makes the class
huge.
a suggested refactoring is to separate
out these concerns into different
Caution: abstractions and make the Component
Key classes class use these abstractions via
Auto-generated code delegation.

Restricted © Siemens AG 2018


Page 84 04.06.2018 Slide 84 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 85 04.06.2018 Slide 85 CT RDA SSI RSE-IN
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”)

Restricted © Siemens AG 2018


Page 86 04.06.2018 Slide 86 CT RDA SSI RSE-IN
Refactoring Cyclically-dependent Modularization

Restricted © Siemens AG 2018


Page 87 04.06.2018 Slide 87 CT RDA SSI RSE-IN
Refactoring Cyclically-dependent Modularization

Restricted © Siemens AG 2018


Page 88 04.06.2018 Slide 88 CT RDA SSI RSE-IN
Refactoring Cyclically-dependent Modularization

Restricted © Siemens AG 2018


Page 89 04.06.2018 Slide 89 CT RDA SSI RSE-IN
Refactoring Cyclically-dependent Modularization

Restricted © Siemens AG 2018


Page 90 04.06.2018 Slide 90 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 91 04.06.2018 Slide 91 CT RDA SSI RSE-IN
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).

Restricted © Siemens AG 2018


Page 92 04.06.2018 Slide 92 CT RDA SSI RSE-IN
Refactoring for Hub-like Modularization

Multiple responsibilities – split the


responsibilities by applying move class
refactoring (create new classes if
required).

Apply “Chain of Responsibility” pattern

Caution:
Core abstractions (example - java.lang.Class has more than 1000 incoming and 40
outgoing dependencies)

Restricted © Siemens AG 2018


Page 93 04.06.2018 Slide 93 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 94 04.06.2018 Slide 94 CT RDA SSI RSE-IN
Outline

Introduction

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring design smells in practice

Restricted © Siemens AG 2018


Page 95 04.06.2018 Slide 95 CT RDA SSI RSE-IN
The principle of Hierarchy

• Hierarchical organization of abstractions via


Hierarchy • Generalization and factoring
Restricted © Siemens AG 2018
• Classification and ordering
Page 96 04.06.2018 Slide 96 CT RDA SSI RSE-IN
Enabling techniques for Hierarchy

Restricted © Siemens AG 2018


Page 97 04.06.2018 Slide 97 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 98 04.06.2018 Slide 98 CT RDA SSI RSE-IN
Unnecessary Hierarchy

This smell arises when the whole inheritance hierarchy is unnecessary,


indicating that inheritance has been applied needlessly for the particular

design context.

Are the subtypes having specialized behavior when compared to the base class?
Since the actual rendering of the line with different styles is done by the OS,
supertype and subtypes have same behavior.
Restricted © Siemens AG 2018
Page 99 04.06.2018 Slide 99 CT RDA SSI RSE-IN
Refactoring Unnecessary Hierarchy

Restricted © Siemens AG 2018


Page 100 04.06.2018 Slide 100 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 101 04.06.2018 Slide 101 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 102 04.06.2018 Slide 102 CT RDA SSI RSE-IN
Unfactored Hierarchy

This smell arises when there is unnecessary duplication among types in a


hierarchy. Two forms of this smell:
• Duplication in sibling types
• Duplication in super and subtypes

Restricted © Siemens AG 2018


Page 103 04.06.2018 Slide 103 CT RDA SSI RSE-IN
Refactoring for Unfactored Hierarchy

Caution:
Inadequate language support to avoid duplication
Lack of support for multiple inheritance (in which case consider delegation
as the solution) or generics for primitive types (e.g. Java)

Restricted © Siemens AG 2018


Page 104 04.06.2018 Slide 104 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 105 04.06.2018 Slide 105 CT RDA SSI RSE-IN
Rebellious Hierarchy

This smell arises when a subtype rejects the methods provided by its
supertype(s):
• throw an exception,
• provide an empty (or NOP i.e., NO Operation) method
• provide a method definition that just prints “should not implement”
message

Restricted © Siemens AG 2018


Page 106 04.06.2018 Slide 106 CT RDA SSI RSE-IN
Suggested refactoring for Rebellious Hierarchy?

Restricted © Siemens AG 2018


Page 107 04.06.2018 Slide 107 CT RDA SSI RSE-IN
Suggested refactoring for Rebellious Hierarchy?

Restricted © Siemens AG 2018


Page 108 04.06.2018 Slide 108 CT RDA SSI RSE-IN
Suggested refactoring for Rebellious Hierarchy?

Restricted © Siemens AG 2018


Page 109 04.06.2018 Slide 109 CT RDA SSI RSE-IN
Rebellious Hierarchy

Caution:
Yet-to-be implemented functionality
Performance considerations
Some specific types may override supertype methods with
NOP to improve performance, because those methods are
actually unnecessary for those specific subtypes and invoking
methods on them will lead to unnecessary computation
overhead
E.g. DefaultListCellRenderer subtype of JLabel overrides
validate, invalidate, revalidate, repaint, isOpaque methods
with empty implementation

Restricted © Siemens AG 2018


Page 110 04.06.2018 Slide 110 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 111 04.06.2018 Slide 111 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 112 04.06.2018 Slide 112 CT RDA SSI RSE-IN
Broken Hierarchy

This smell arises when a supertype and its subtype conceptually do


not share an “IS-A” relationship resulting in broken substitutability.

Restricted © Siemens AG 2018


Page 113 04.06.2018 Slide 113 CT RDA SSI RSE-IN
Refactoring Broken Hierarchy

Restricted © Siemens AG 2018


Page 114 04.06.2018 Slide 114 CT RDA SSI RSE-IN
Refactoring Broken Hierarchy

Caution:
Class adapter pattern

Restricted © Siemens AG 2018


Page 115 04.06.2018 Slide 115 CT RDA SSI RSE-IN
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();
}
Restricted © Siemens AG 2018 // rest of the code elided …
Page 116 04.06.2018 Slide 116 CT RDA SSI RSE-IN
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.

Restricted © Siemens AG 2018


Page 117 04.06.2018 Slide 117 CT RDA SSI RSE-IN
Refactoring for Missing Hierarchy

Restricted © Siemens AG 2018


Page 118 04.06.2018 Slide 118 CT RDA SSI RSE-IN
Refactoring for Missing Hierarchy (1)
public Insets getBorderInsets(Component c, Insets insets){
Insets margin = null;
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();
}

public Insets getBorderInsets(IMargin c, Insets insets){


Insets margin = null;
margin = c.getMargin();
}

Restricted © Siemens AG 2018


Page 119 04.06.2018 Slide 119 CT RDA SSI RSE-IN
Refactoring for Missing Hierarchy (2)
public Insets getBorderInsets(Component c, Insets insets){
Insets margin = null;
if (c instanceof AbstractButton) {
margin = ((AbstractButton)c).getMargin(); Caution:
} else if (c instanceof JToolBar) { Reading a configuration file
margin = ((JToolBar)c).getMargin(); to alter the runtime
} else if (c instanceof JTextComponent) { configuration
margin = ((JTextComponent)c).getMargin(); Instantiating objects using a
} factory

public Insets getBorderInsets(Component c, Insets insets){


Insets margin = null;
if (c instanceof IMargin) {
margin = c.getMargin();
} // rest of the code elided
Restricted © Siemens AG 2018
Page 120 04.06.2018 Slide 120 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 121 04.06.2018 Slide 121 CT RDA SSI RSE-IN
Wide Hierarchy

This smell arises when an inheritance hierarchy is “too” wide and shallow
indicating that intermediate types may be missing.

Restricted © Siemens AG 2018


Page 122 04.06.2018 Slide 122 CT RDA SSI RSE-IN
Refactoring for Wide Hierarchy

Restricted © Siemens AG 2018


Page 123 04.06.2018 Slide 123 CT RDA SSI RSE-IN
Suggested refactoring for Wide Hierarchy

Caution:
Language/library could require extending a type (ListResourceBundle manages
resources for a locale and is a class extended by 443 classes.)
Restricted © Siemens AG 2018
Page 124 04.06.2018 Slide 124 CT RDA SSI RSE-IN
Developer expects to
support an annotated
report in future

Restricted © Siemens AG 2018


Page 125 04.06.2018 Slide 125 CT RDA SSI RSE-IN
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)

Restricted © Siemens AG 2018


Page 126 04.06.2018 Slide 126 CT RDA SSI RSE-IN
Refactoring Speculative Hierarchy

Restricted © Siemens AG 2018


Page 127 04.06.2018 Slide 127 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 128 04.06.2018 Slide 128 CT RDA SSI RSE-IN
Deep Hierarchy

This smell arises when an inheritance hierarchy is excessively


deep

Restricted © Siemens AG 2018


Page 129 04.06.2018 Slide 129 CT RDA SSI RSE-IN
Refactoring for Deep Hierarchy

“Collapse” interfaces/classes
• InterruptibleChannel interface is a marker
interface that can be removed (annotations
made marker interfaces irrelevant)
• SelectableChannel abstract class contains a
few method declarations and only one
method definition that can be pushed to its
subclass.

Restricted © Siemens AG 2018


Page 130 04.06.2018 Slide 130 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 131 04.06.2018 Slide 131 CT RDA SSI RSE-IN
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.

Restricted © Siemens AG 2018


Page 132 04.06.2018 Slide 132 CT RDA SSI RSE-IN
Suggested refactoring for Multipath Hierarchy

Restricted © Siemens AG 2018


Page 133 04.06.2018 Slide 133 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 134 04.06.2018 Slide 134 CT RDA SSI RSE-IN
Cyclic Hierarchy

This smell arises when a supertype in a hierarchy depends on any of its


subtypes.
This dependency could be in the following forms:
• a supertype contains an object of one of its subtypes
• a supertype refers to the type name of one of its subtypes
• a supertype accesses data members, or calls methods defined in one of
its subtypes.

Restricted © Siemens AG 2018


Page 135 04.06.2018 Slide 135 CT RDA SSI RSE-IN
Refactoring Cyclic Hierarchy

Restricted © Siemens AG 2018


Page 136 04.06.2018 Slide 136 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 137 04.06.2018 Slide 137 CT RDA SSI RSE-IN
Outline

Introduction

Abstraction smells

Encapsulation smells

Modularization smells

Hierarchy smells

Refactoring design smells in practice

Restricted © Siemens AG 2018


Page 138 04.06.2018 Slide 138 CT RDA SSI RSE-IN
How to improve design quality in practice?

Restricted © Siemens AG 2018


Page 139 04.06.2018 Slide 139 CT RDA SSI RSE-IN
Refactoring process model

Restricted © Siemens AG 2018


Page 140 04.06.2018 Slide 140 CT RDA SSI RSE-IN
Tools

Comprehension tools
Imagix 4D, Structure 101
Critique, code-clone detectors, and metric tools
Infusion, Designite, Ndepend
Simian, CPD
Understand, Source-monitor, Designite
Technical debt quantification and visualization tools
Sonar Qube
Refactoring tools
Refactoring inferencing tools – SCOUT, Jdeoderant
Refactoring performing tools – Eclipse, Resharper

Restricted © Siemens AG 2018


Page 141 04.06.2018 Slide 141 CT RDA SSI RSE-IN
Key takeaways and conclusion

Design quality is important for software Design smells can be viewed as violation
(especially in case of large, complex, of underlying fundamental design
and/or reusable software) principles

A great designer is one who understands Some design smells can’t be fixed
the impact of design defects/smells and For such smells, the only way is to
knows how to address them avoid introducing them in the first
place!
Design smells are candidates for
refactoring Context is important for smells
Given the liability of a smell, in
certain contexts, a designer may
make a conscious decision to live
with that smell

Restricted © Siemens AG 2018


Page 142 04.06.2018 Slide 142 CT RDA SSI RSE-IN
Suggested Reading

Restricted © Siemens AG 2018


Page 143 04.06.2018 Slide 143 CT RDA SSI RSE-IN
Our book on this topic!

Restricted © Siemens AG 2018


Page 144 04.06.2018 Slide 144 CT RDA SSI RSE-IN
Restricted © Siemens AG 2018
Page 145 04.06.2018 Slide 145 CT RDA SSI RSE-IN
References

Restricted © Siemens AG 2018


Page 146 04.06.2018 Slide 146 CT RDA SSI RSE-IN
Thank you!

Restricted © Siemens AG 2018


Page 147 04.06.2018 Slide 147 CT RDA SSI RSE-IN
Dr. Girish Suryanarayana
Senior Key Expert
CT RDA SSI SDT-IN
[email protected]

Shrinath Gupta
Technical Expert
Thank you! CT RDA SSI SDT-IN
[email protected]

Shubham Sahu
Associate Engineer
CT RDA DS AA TEC
[email protected]

Restricted © Siemens AG 2018


Page 148 04.06.2018 CT RDA SSI RSE-IN

You might also like