Formal refactoring transformations include superclass abstraction, conditional elimination,
and aggregate abstraction. These formal refactorings originated in Opdyke’s PhD thesis [Opdyke 92]. They are called formal refactorings because implementations can be proven not to affect program correctness. It’s also possible to automate these transformations. The following refactorings involve changes to object classes, implementations, and relationships. • Superclass abstraction. This refactoring applies to two or more similar classes. A
superclass abstraction creates an abstract class that merges the common
implementations of several concrete classes. To perform a superclass abstraction, the program transformation involves: (a) transformation of similar method signatures to common method signatures, (b) creation of an abstract superclass, (c) code modification to merge selected implementations, and (d) migration of common methods to the abstract superclass.
• Conditional elimination. This refactoring applies when the structure and behavior of a
class is heavily dependent upon a conditional statement. The steps are: (a) create new subclasses corresponding to each condition, (b) migrate the action code from the conditional to the new subclasses, and (c) redirect class references to refer to the
subclass types as appropriate. This last change can affect constructors, type declarations, and invocations of overloaded methods. The modified references should maintain the original logical states from the conditional, as invariant assertions on the new classes. • Aggregate abstraction. An aggregate abstraction reorganizes class relationships to
improve their structure and extensibility. This transformation can take several forms: (a) conversion of inheritance relationships to aggregate relationships, (b) migration of
aggregated classes to component relationships, or (c) migration of component relationships to aggregate relationships.
These three, large−grain refactorings are dependent upon dozens of small−grain program transformations [Opdyke 92], which are familiar to virtually all programmers. Examples of small−grain transformations include: (a) renaming classes, methods, and attributes; (b) creating new classes; (c) migrating functionality between classes; (d) converting direct references to indirect pointers, and so forth. For a complete list, consult Opdyke (1992).
Development AntiPattern Summaries
Development AntiPatterns utilize various formal and informal refactoring approaches. The following summaries provide an overview of the Development AntiPatterns found in this chapter and focus on the development AntiPattern problem. Included are descriptions of both development and mini−AntiPatterns. The refactored solutions appear in the appropriate AntiPattern templates that follow the summaries.
The Blob: Procedural−style design leads to one object with a lion’s share of the
responsibilities, while most other objects only hold data or execute simple processes. The solution includes refactoring the design to distribute responsibilities more uniformly and isolating the effect of changes.
Continuous Obsolescence: Technology is changing so rapidly that developers often have trouble keeping up with current versions of software and finding combinations of product releases that work together. Given that every commercial product line evolves through new releases, the situation is becoming more difficult for developers to cope with. Finding compatible releases of products that successfully interoperate is even harder. Lava Flow: Dead code and forgotten design information is frozen in an ever−changing design. This is analogous to a Lava Flow with hardening globules of rocky material. The refactored solution includes a configuration management process that eliminates dead code and evolves or refactors design toward increasing quality.
Ambiguous Viewpoint: Object−oriented analysis and design (OOA&D) models are often presented without clarifying the viewpoint represented by the model. By default, OOA&D models denote an implementation viewpoint that is potentially the least useful. Mixed viewpoints don’t allow the fundamental separation of interfaces from implementation details, which is one of the primary benefits of the object−oriented paradigm. Functional Decomposition: This AntiPattern is the output of experienced, nonobject−oriented developers who design and implement an application in an object−oriented language. The resulting code resembles a structural language (Pascal, FORTRAN) in class structure. It can be incredibly complex as smart procedural developers devise very “clever” ways to replicate their time−tested methods in an object−oriented architecture.
Poltergeists: Poltergeists are classes with very limited roles and effective life cycles. They often start processes for other objects. The refactored solution includes a reallocation of responsibilities to longer−lived objects that eliminate the Poltergeists. Boat Anchor: A Boat Anchor is a piece of software or hardware that serves no useful purpose on the current project. Often, the Boat Anchor is a costly acquisition, which makes the purchase even more ironic.
Golden Hammer: A Golden Hammer is a familiar technology or concept applied obsessively to many software problems. The solution involves expanding the knowledge of developers through education, training, and book study groups to expose developers to alternative technologies and approaches.
Dead End: A Dead End is reached by modifying a reusable component if the modified component is no longer maintained and supported by the supplier. When these
modifications are made, the support burden transfers to the application system developers and maintainers. Improvements in the reusable component are not easily integrated, and support problems can be blamed upon the modification.
Spaghetti Code: Ad hoc software structure makes it difficult to extend and optimize code. Frequent code refactoring can improve software structure, support software maintenance, and enable iterative development.
Input Kludge: Software that fails straightforward behavioral tests may be an example of an input kludge, which occurs when ad hoc algorithms are employed for handling program input.
Walking through a Minefield: Using today’s software technology is analogous to
walking through a high−tech mine field [Beizer 97a]. Numerous bugs are found in released software products; in fact, experts estimate that original source code contains two to five bugs per line of code.
Cut−and−Paste Programming: Code reused by copying source statements leads to significant maintenance problems. Alternative forms of reuse, including black−box reuse, reduce maintenance issues by having common source code, testing, and documentation. Mushroom Management: In some architecture and management circles, there is an explicit policy to keep system developers isolated from the system’s end users. Requirements are passed second−hand through intermediaries, including architects, managers, or requirements analysts.
In addition to the preceding AntiPatterns, this chapter includes a number of mini−AntiPatterns that represent other common problems and solutions.
The Blob
AntiPattern Name: The Blob
Also Known As: Winnebago [Akroyd 96] and The God Class [Riel 96] Most Frequent Scale: Application
Refactored Solution Name: Refactoring of Responsibilities Refactored Solution Type: Software
Root Causes: Sloth, Haste
Unbalanced Forces: Management of Functionality, Performance, Complexity Anecdotal Evidence: “This is the class that is really the heart of our architecture.”
Background
Do you remember the original black−and−white movie The Blob? Perhaps you saw only the recent remake. In either case, the story line was almost the same: A drip−sized, jellylike alien life form from outer space somehow makes it to Earth. Whenever the jelly thing eats (usually unsuspecting earthlings), it grows. Meanwhile, incredulous earthlings panic and ignore the one crazy scientist who knows what’s happening. Many more people are eaten before they come to their senses. Eventually, the Blob grows so large that it threatens to wipe out the entire planet. The movie is a good analogy for the Blob AntiPattern, which has been known to consume entire object−oriented architectures (see Figure 5.1).