CSC/ECE 517 Fall 2009/wiki3 1 co
Software Design Anti-Patterns
Not all patterns are good. Anti-patterns are patterns that initially seem effective, but over time you learn that they lead you into traps. - Scott Klement, Anti-Patterns: Avoid the Programming Dark Side
In this article, we will describe several software design patterns which have been categorized as "anti patterns": Programming approaches which are not uncommon and which can lead to poor program design and performance.
What are Anti-Patterns?
Different texts define the term anti-patterns in different ways:
- "An AntiPatern is a literary form that describes a commonly occurring solution to a problem that generates decidedly negative consequences." - AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis
- "Anti-patterns are patterns that initially seem effective, but over time you learn that they lead you into traps." - Anti-Patterns: Avoid the Programming Dark Side
- Over the last decade we have witnessed the maturity of both best practices...and worst practices (as manifested in the anti-patterns movement...). - Patterns of Anti-Patterns?, Journal of Object Technology
In each definition, the implementer of the anti-pattern is trying to solve a problem in a common way, however the common way is a bad design that can lead to unintended consequences. Some of the reasons cited in the AntiPatterns book as to why these anti-patterns have been used include: Haste, sloth (or laziness), ignorance, apathy, and pride. Studying anti-patterns can at least help assist the potential anti-pattern implementer in the ignorance category.
Considerations When Writing Anti-Patterns
When writing patterns, there are various templates to from which to choose, for example, the pattern template from the Gang of Four's Design Pattern book:
- Pattern Name and Classification
- Intent
- Also Known As
- Motivation
- Applicability
- Structure
- Participants
- Collaboration
- Consequences
- Implementation
- Sample Code
- Known Uses
- Related Patterns
Brown et al in their book AntiPatterns suggest 3 different possible templates for writing anti-patterns:
- Pseudo-AntiPattern Template: Only the name and problem are described
- Mini-AntiPattern Template: Includes the name, AntiPattern Problems, and Refactored Solution
- Full AntiPattern Template: Includes 18 different sections such as Root Causes, Background, Known Exceptions, and Examples.
For the purposes of brevity, this wiki page will use the Mini-AntiPattern Template form with the addition of an Example section.
Anti-Pattern Examples
This section presents six anti-patterns from the book AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis.
The Blob or God Class
Anti-Pattern Problem
A design includes a class that has the majority of attributes and/or methods in the system. According to Brown et al, this anti-pattern could be the result of using a procedural design in an object-oriented language, and therefore imbuing one of the classes with the majority of the methods and seeing that class as a "controller" class. Another sign that the Blob anti-pattern may be present is if a class is designated as a "utility" class, which indicates a possible catch-all class for unrelated classes.
Refactored Solution
Brown et al suggests refactoring responsibilities into appropriate classes using the following steps:
- Identify cohesive sets of operations and attributes that relate to a common focus, behavior, or function.
- Review the system to see if there are "natural homes" for these collections in existing classes.
- Remove redundant or "far-coupled" associations.
- Migrate associates to derived classes to a common base class.
- Remove all transient associations, replacing them as appropriate with type specifiers to attributes and operations arguments.
Example
An inappropriate use of the Rails framework, where a majority of the methods reside in a single controller class or model class. To resolve the issues, helper classes or other classes could be created which would more appropriately contain related methods that were inappropriately kept in a controller or model.
Lava Flow
Anti-Pattern Problem
A design includes obsolete technologies or unused or misunderstood extensions. This problem usually occurs when prototype or research code is used as the basis for a production system, or when a code base has existed over a long period of time and the code base was not updated to reflect changes in surrounding technologies or systems.
Refactored Solution
Often times, the presence of obsolete or unused code is the result of lacking a sound design and architecture that is followed and updated throughout the system lifecycle. To resolve the issue of obsolete code, a redefinition of the architecture is necessary, with removal of "dead" code as the system is refactored to the new architecture. There is no easy fix for this issue, and it will take time to reengineer the system to remove redundancy and obsolescence.
Example
A financial program that helps customers manage their stock portfolio was developed as a web application with using HTML 2.0 and Java 1.3 servlets. Over time, the program was enhanced by building on the existing code base. Eventually the system was upgraded to serving XHTML 5 pages and using Java 6 in the server. Because of the lack of comprehensive design and architectural documentation, portions of the code use depracated methods and badly formatted HTML in places because the current development team does not understand the system to know what is "safe" to change or remove.
Poltergeists or Gypsy
Anti-Pattern Problem
A design which includes classes that have minimal responsibilities and roles in the system. These "poltergeists" appear only briefly in the system, possibly to invoke methods of other classes. Brown et al indicates these classes are usually a sign of an inexperienced OO developer who has overdesigned the system.
Refactored Solution
Simply removed the "poltergeists" from the system altogether and then move the functionality to a related class.
Example
A developer is writing the software for an automated label printing system. He decides to create a SystemController class which drives all the actions within the system (move label to printer, extract label information from database, print label, eject printed label). Other than directing the actions of the other classes, the SystemController has no other purpose, and is effectively a "poltergeist". In this situation, an object-oriented design may not even be warranted, and a procedural design may be more appropriate.
Golden Hammer
Anti-Pattern Problem
A system overuses a solution or vendor product to the detriment of the design and system itself. This can occur if a developer or development team has gotten comfortable with an approach or technology, and keeps going back to that approach or technology as the answer to all problems. Additionally, a development team may find itself forced into that situation for business reasons if their company has invested heavily in a product or technology and is expecting a return on that investment.
Refactored Solution
The refactoring for this anti-pattern involves a change in mindset as well as a software changes. The development team must acknowledge the appropriate use and limitations of the "favored" technology. Other approaches should be investigated and weighed fairly against each other. Where investments are involved, management may be needed to step in to make sure that technology investments are more evenly distributed.
Example
A developer new to Ruby on Rails needs to create a new data structure. Having created several models which also create new database tables, the developer defaults to creating another model which adds a new table to the database. This approach is not recommended for transient data when instead a simple class with attributes would suffice.
Spaghetti Code
Anti-Pattern Problem
A system appears to have little software structure. This type of anti-pattern can result when developers code first, and then possibly attempt to design along the way. The code with this issue is often difficult to understand, maintain, or enhance. The system is very closed and does not lend itself to reuse.
Refactored Solution
The solution in this case is to perform a major refactoring or clean-up on the system. Initially the goal should be to achieve an overall structure that is sensible, and then move toward improving performance and internal structures.
Example
A development team quickly creates a working prototype of a grade book, and are then pushed to provide a production version within 2 months. The working prototype actually has 80% of the function available, so the team works from that base to complete the production version. In the process of creating the prototype, the team gave little thought to design and extensibility, and they had no time when creating the production version to produce a product that could be easily extended.
Cut-and-Paste Programming
Anti-Pattern Problem
An implementation contains "cloned" code throughout the project. A developer needs to solve a particular problem in his code which has already been implemented in a different section of code. He finds he can quickly gain the new function by just copying the original code to the new location. Problems occur when unknown bugs in the original code are replicated to the new code. Further, it is more difficult to enhance the code because one must know multiple places to make changes.
Refactored Solution
Cloned code can be refactored either through use of a common method or through inheritance. Additionally, going forward, a development team can attempt to identify likely code which should be usable, and they can design the code to exist in a reusable method or class.
Example
A developer is attempting to solve an issue in his section of the code which he knows has been solved in another area. He finds that he can quickly copy the foreign code into his code and resolve his issue. He knows that he could create a common method or class that he and the other code section could use, but he chooses not to do that because of the coordination with other developers that would be involved.
Conclusion
Reviewing anti-patterns can be very beneficial to help you avoid the common pitfalls that inexperienced (and sometimes experienced) software developers fall in when writing software. Besides identifying design issues, anti-patterns can also give insight into the group dysfunction and business realities that also influence the production of software. Just as design patterns offer a shortcut for architects and developers in talking about implementation, anti-patterns can also offer a shortcut for describing issues to developers and others. Knowing about anti-patterns can also offer some comfort when the inevitable mistakes are made.
References
- www.antipatterns.com
- W. J. Brown et al., AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis, John Wiley & Sons, Inc., New York, NY, 1998.
- S. Klement, Anti-Patterns: Avoid the Programming Dark Side, 2008
- Wikipedia entry: Anti-pattern
- Anti Patterns Catalog offered by Cunningham & Cunningham, Inc.
- What is an AntiPattern? from Sourcemaking.com
- Anti-Patterns and Worst Practices – You’re Doing it Wrong!
- M. H. Dodani,Patterns of Anti-Patterns?, Journal of Object Technology, Vol 5, No 6, pp 29-33, 2006
- E. Gamma et al,Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley Professional, 1994.
- G. Meszaros and J. Doble, A Pattern Language for Pattern Writing.