Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 35

Subject : CODE REENGINEERING

Year : 2017

Hierarchy Smell
Session 21 & 22
Learning Outcomes

LO 2: Apply Advanced refactoring and its application


LO 3: Formulate suitable refactoring for code environment

COMP6047 - Algorithm and Programming


Sub Topics

- Missing Hierarchy
- Unnecessary Hierarchy
- Unfactored Hierarchy
- Wide Hierarchy
- Speculative Hierarchy
- Deep Hierarchy
- Rebellious Hierarchy
- Broken Hierarchy
- Multipath Hierarchy
- Cyclic Hierarchy

COMP6047 - Algorithm and Programming


Hierarchy Smell

The principle of hierarchy advocates the creation of a hierarchical organization


of abstractions using techniques such as classification, generalization,
substitutability, and ordering.
Hierarchy Principle Enabling
Hierarchy Principle Enabling
Apply meaningful classification. Classify types to create a hierarchical
organization using the following two steps: 1. Identify commonalities and
variations among types. 2. Classify the supertypes and subtypes in levels to
create a hierarchy.

Apply meaningful generalization helps enhance reusability, understandability,


and extensibility of the design. Further, generalization also helps reduce (or
altogether eliminate) code duplication within types in the hierarchy.

Ensure substitutability. Ensure that the types in the hierarchy follow the
Liskov’s Substitution Principle (LSP); in other words, a reference of a supertype
can be substituted with objects of its subtypes without altering the behavior of the
program.

Avoid redundant paths. An inheritance hierarchy allows us to explicitly express


the logical relationship between related types. When there are redundant paths in
an inheritance hierarchy, it unnecessarily complicates the hierarchy.

Ensure proper ordering. The key benefit of a hierarchical organization stems


from its ability to provide us with a means to address the complex relation- ships
among types.
Hierarchy Smell
Hierarchy Smell
Design Smell and Violated Hierarchy
Technique

Violated Enabling Technique Design Smell


Apply meaningful Classification Missing hierarchy, Unnecessary
hierarchy
Apply meaningful generalization Unfactored hierarchy, Wide Hierarchy,
Speculative Hierarchy, Deep Hierarchy
Ensure Substitutability Rebellious Hierarchy, Broken Hierarchy
Avoid redundant path Multipath Hierarchy
Ensure proper ordering Cyclic Hierarchy
Missing Hierarchy
Component Description
Definition This smell arises when a code segment uses conditional logic
(typically in conjunction with “tagged types”) to explicitly
manage variation in behavior where a hierarchy could have
been created and used to encapsulate those variations.
Rationale Switch-based-on-type-codes (or chained if-else statements) is
one of the most well- known design smells. When type
information is encoded (for example, using an enumeration, an
integral value, or a string), variation in behavior is not
encapsulated properly.
Potential Causes • Misguided simplistic design
• Procedural approach design
• Overlooking inheritance as design technique
Missing Hierarchy Example

The chained if-else code block has explicit type checks for AbstractButton, JToolBar, and
JTextComponent. The code where the getMargin() method is called is the same within all
the conditions. As one can observe from the inline comments, the concerned
developer consciously chose a hack, and in that process introduced this smell in
design. Note that the explicit type checks as shown above is repeated in two other
places in the same source file.
Missing Hierarchy Example
Refactoring

For the java.swing.plaf.windows.XPStyle.java example, a


potential refactor- ing is provided in the code comment
itself: “Ideally we’d have an interface defined for
classes which support margins (to avoid this hackery).”
Clearly, a refactoring suggestion would be to create an
interface that declares methods such as getMargin() and
setMargin(). Classes such as AbstractButton, JToolBar, and
JTextCompo- nent that support the concept of margins can
implement that interface
Impacted Quality
Understandability—When compared to the equivalent code that makes use of
runtime polymorphism through a hierarchy, using switch-based-on-type-codes
and tagged types increases the complexity of the code base and thus impacts the
understandability of the design.

Changeability and Extensibility—A hierarchy helps encapsulate variation and


hence it is easy to modify existing types or add support for new types within that
hierarchy without affecting the client code.

Reusability—Consider the encoding example where the type information is


provided in a tagged type in a class and the behavior is spread across the
conditional statements in the client code.

Testability—When this smell is present, there would be numerous conditional


statements in code with slightly different behavior.

•Reliability—This smell can impact reliability in many ways. Some of the ways
are:
• A common problem when using type-based checking is that a developer
may miss out on some of the checks for type codes.
Practical Consideration (Reification)

Interacting with the external world

File formats usually “mark” the data content within the file to indicate the type of
the data (for instance, the file format for .class in Java). This encoding helps read
data from the flat-file: the program needs to first check the type information of
the data and then process the data.
Unnecessary Hierarchy

Component Description
Definition This smell arises when the whole inheritance hierarchy is
unnecessary, indicating that inheritance has been applied
needlessly for the particular design context.
Rationale For effective application of the principle of hierarchy, it is
important to adhere to the enabling technique “apply
meaningful classification.” For a “meaningful” application of
classification, the focus should be more on capturing the
commonalities and variation in behavior rather than data.
Potential Causes • Subclasses instead instantiating
• Taxonomy Mania
Missing Hierarchy Example
Consider the case of a text editor that supports multiple fonts. In this application,
when the user selects the font, the editor just passes this information to the
underlying OS which renders the text in the selected font. Figure shows how
inheritance can be used to support multiple fonts in such an editor - Font is the
supertype and fonts such as Arial and Calibri are supported via Font’ s subtypes
named ArialFont and CalibriFont. However, if we were to reflect on this design, we will
realize that since the editor does not change its behavior based on the font,
classifying the types of fonts within a hierarchy is unnecessary. Hence, this design
suffers from Unnecessary Hierarchy smell.
Missing Hierarchy Example
Refactoring

In the case of Font hierarchy, the suggested refactoring solution is to make the
subtypes of Font into objects of Font, such as Arial and Calibri objects. But note that
another possible refactoring is to model this list of fonts as an enumeration
(Figure 6.11). Choosing the correct refactoring option would depend on the
context.
Impacted Quality
Understandability—If a hierarchy is created unnecessarily, it complicates the
design. Hence, this smell impacts understandability of the design.

Extensibility—Consider Example 2 wherein the number of types in a hierarchy


can grow exponentially when new combinations need to be supported in the
design.

Testability—It requires more effort to test numerous types in an Unneces- sary


Hierarchy when compared to testing an alternative solution (e.g., one that uses
an enumeration or a class).
Practical Consideration (Reification)

None
Unfactored Hierarchy

Component Description
Definition Duplication in sibling types: Sibling types in the hierarchy have
similar code segments that can be moved into one of their
supertypes.
Duplication in super and subtypes: There are similar code
segments in super and subtypes indicating redundant code in
the subtypes.
Rationale If the common interface across types is elevated in the
hierarchy, clients can depend on this common interface rather
than the concrete implementation aspects of the subtypes.
If duplicated implementation across types in the hierarchy is
removed by elevating the implementation to a supertype,
unnecessary duplication across the types is avoided.
Potential Causes • Copying subtype
• Improve handling of outlier
Unfactored Hierarchy Example
The abstract class java.text.NumberFormat in JDK 7 provides support for for-
matting and parsing numbers in any locale. It has two subclasses: ChoiceFormat
and DecimalFormat. With ChoiceFormat, we can attach a format to a range of
numbers and with DecimalFormat, we can format decimal numbers for any
locale

The classes in the


NumberFormat hierarchy
support the use of a
pattern for for- matting.
For example, in the
pattern “###,###.##,”
the symbol “#” stands
for a digit, the comma
is the thousands-
separator and the period
represents the decimal
point.
Unfactored Hierarchy Example Refactoring

In the case of NumberFormat example, the signature of two methods is the same in
the subclasses and their implementations are different. Hence, a suggested
refactoring is to introduce abstract methods applyPattern() and toPattern() in the
supertype NumberFormat
Impacted Quality
Understandability—Duplication within the hierarchy unnecessarily bloats the
code and increases the cognitive load on developers.

Changeability and Reliability—A change to the code that is common across a set
of types needs to be replicated across all those types, failing which a defect may
occur.

Extensibility—When this smell exists in a hierarchy, introducing a new subtype in


the hierarchy can require more work. Since commonality is not exploited in the
hierarchy, it is possible that fields, methods, or interface may need to be
duplicated in the new subtype.
Practical Consideration (Reification)

Inadequate language support to avoid duplication

Consider a hierarchy where two sibling classes have a duplicate implementation.


We could factor out the common implementation to their superclass, but we have
to make sure that we don’t introduce other smells in the process or make the
design overly complex.
Wide Hierarchy

Component Description
Definition This smell arises when an inheritance hierarchy is “too” wide
indicating that intermediate types may be missing.
Rationale • Missing intermediate types may force the clients of that
hierarchy to directly refer to the subtypes. This dependency
affects the changeability and extensibility of the hierarchy.
• There may be unnecessary duplication within types (since
commonality cannot be properly abstracted due to lack of
intermediate types).
Potential Causes • Ignoring generalization
• Lack of refactoring
Wide Hierarchy Example

Consider the java.util.EventObject class which is the superclass of 36 immediate


subclasses. The partial hierarchy of this class is shown in Figure 6.18! Since this
hierarchy has a large number of sibling classes, it exhibits the Wide Hierarchy
smell.
Wide Hierarchy Example Refactoring
Impacted Quality
Understandability— when intermediate abstractions are missing, the sibling
classes are not at the same level of abstraction and the programmer has to do a
“logical leap” to move from higher levels of abstraction to much lower levels of
abstraction. This impacts the understandability of the hierarchy.

Extensibility—One of the advantages of a properly designed hierarchy is that the


types serve as “hook points” or “placeholders” for future extensions. Since some
intermediate types are missing in the hierarchy, it affects the extensibility of the
hierarchy.

Reusability—An advantage of a properly designed hierarchy is that the types


serve as interfaces to client code. Since some intermediate abstractions are
missing in a Wide Hierarchy, it reduces the reusability of the hierarchy.
Practical Consideration (Reification)

Language or library could require extending a type

Using an interface for specifying a protocol


Speculative Hierarchy

Component Description
Definition This smell arises when one or more types in a hierarchy are
provided speculatively (i.e., based on imagined needs rather
than real requirements).
Rationale One of the key enabling techniques for the effective application
of the principle of hierarchy is “apply meaningful
generalization.” Generalization should be performed for
exploiting commonalities in existing types
Potential Causes • Future-proofing
• Over-engineering
Wide Hierarchy Example

Consider the inheritance


hierarchy given in. What is
interesting about this hierarchy
is that the supertypes have
exactly one subtype (making it
look like a “list”). This hierarchy
was part of a code analyzer tool
that statically analyzed the
source code and reported
potential defects in the source
code. One of the features of this
tool was its support for
generating HTML reports. It was
also planned that this tool
would support reports in other
formats (such as .doc, .rtf,
and .pdf) in the future.
Wide Hierarchy Example Refactoring
In the discussed example, the current need for
the tool is the ability to generate HTML
reports. Since the AnnotatedReport type is based
on a speculated need, it could be removed from
the hierarchy (refer Figure 6.22). It should be
pointed out that it is acceptable to have the
AbstractReport and DefaultReport in the hierar- chy
because the support for different types of
reports is part of the product roadmap.
Impacted Quality
Understandability—If one or more types in a hierarchy are added speculatively, it
unnecessarily complicates the design. Hence, this smell impacts the
understandability of the design.

Testability—It may require more effort to test unnecessary generic types in the
hierarchy when compared to testing a hierarchy without speculative types. This
impacts the testability of the overall design.
Practical Consideration (Reification)

None
References

Girish Suryanarayana, Ganesh Samarthyam and Tushar Sharma, Chapter 2 - Design Smells, In
Refactoring for Software Design Smells, edited by Girish Suryanarayana and Ganesh
SamarthyamTushar Sharma, Morgan Kaufmann, Boston, 2015, Pages 9-19, ISBN
9780128013977, http://dx.doi.org/10.1016/B978-0-12-801397-7.00002-3.

M. Fowler and K. Beck, "Bad Smells in Code," in Refactoring: Improving the Design of
Existing Code, Addison-Wesley, 2000

W. Stevens, G. Myers and L. Constantine, "Structured Design," IBM Syst J, vol. 13, no. 2, pp.
115-139, 1974.

COMP6047 - Algorithm and Programming

You might also like