CSC/ECE 517 Fall 2009/wiki3 1 ab
Antipattern
An AntiPattern describes a commonly occurring solution to a problem that generates negative consequences. The term was coined in 1995 by Andrew Koenig,[3] inspired by Gang of Four's book Design Patterns, which developed the concept of design patterns in the software field. Antipatterns are documented in detail nowadays in software design because identifying bad practices can be as valuable as identifying good practices. A well formulated AntiPattern also tells us why the bad solution looks attractive (e.g. it actually works in some narrow context), why it turns out to be bad, and what positive patterns are applicable in its stead. As an example, consider braking in a car (in the days before antilock brakes): if the conditions involve ice, solving the "I must stop" problem by firmly depressing the brake would be an AntiPattern: it seems like a good idea, but it has a fatal flaw in that firm braking on ice causes skidding and little deceleration. Studying the AntiPattern teaches you to pump the brake, a more appropriate solution Pattern.
AntiPatterns identify and categorize the common mistakes in software practice, which is a target-rich environment for research in AntiPatterns . AntiPatterns also identify alternative solutions and extend the field of design patterns research into exciting new areas and issues, including: refactoring, reengineering, system extension, and system migration.
When Antipatterns are used
The problem of Antipatterns arises mostly when
- Not using any design patterns during design or coding though this will work at the beginning but doubtful if it will withstand the test of times.
- Time becomes the biggest constraint. Agile methodologies dominating the projects arena in the recent times, tend to leave design to the wayside entirely and that has become the popular belief for a proper approach. This fits in perfectly with management’s request of trying to get things done right now no matter what. Refactoring becomes a much bigger part of the process through iterations. However, not attempting to recognize components and apply patterns where applicable before “diving in” and just getting it coded can very negatively effect the project’s long term success.
- Patterns are over used and the situation does not demand it. Just like lack of design patterns usage is an antipattern, overusing patterns is an antipattern too. Extensive use of patterns, when there is not a need makes the code nowhere near maintainable. This in turn, conflicts one of the most important goals of design patterns, code maintainability.
- Creating massive classes with a huge number of methods.
- Too many utility classes that perform too many operations. A utility class is one that has only static methods, no state and which performs operations on objects that are passed in.
- Performing excessive and unnecessary run-time type checks, rather than using the type system to do the work
Anemic Domain Model
BaseBean
God object
Singletonitis
Sequential Coupling
Yo Yo Problem
Object-oriented design anti-patterns - A subset of Software design of Anti patterns
A design anti-pattern in an object-oriented program, just like in software design, is an example of design that initially appeared to be a good idea, but later turned out to be a bad one. Anti-patterns are examples of bad design and bad coding practice. Some examples of object-oriented anti-patterns:
Types of Object-oriented design anti-patterns
Problem: This pattern proposed by Martin Fowler, arises when the logic is typically implemented in separate classes, which transform the state of the domain objects. With the anemic domain model, all the logic is not given with the associated object. It’s located in the objects that use them. So the problem is unless you are using the objects that have the behavior, having the anemic domain model does not do any good. In fact, they just getters and setters with barely enough behaviour to call them objects. So in short, it looks like a model, it smells like a model but there is no behavior inside. It brings in problems like code duplication and maintenance, since the business logic is spread across the business, all the common business logic will need to be updated all at once and validated against their respective service and validation.
Example: A class with a private variable and availability of no code to persist the variable's state.
Solution: The business logic has to go inside your domain model and made easy to understand. Still, if a certain part of the business needs “special” behavior, it will have to be incorporated inside the main domain model such that objects can self validate since the validation logic is located inside of the object.
Problem: In object-oriented programming, a BaseBean is a utility object from which concrete entites are derived (via subclassing). Using inheritance causes the derived class to rely on the internals of a base class which may be out of the control of the developer. While the utility classes are typically stable and fairly similar across implementations, some innocuous change in the future could break the derived class (since the relationship is not well defined). In addition, it muddies the business meaning of the derived class.
Example: A class ComboBox, whose functionality needs to be extended and is done by creating a subclass of ComboBox and adding/overriding appropriate methods.
Solution: A class should not inherit from another class simply because the parent class contains functionality needed in the subclass. Instead, delegation (has-a relationship) should be used to obtain the business logic or data structure that is required. In technical terms, this case warrants composition over inheritance.
Problem: In object-oriented programming, a God object is an object that knows too much or does too much. Concentrating too many methods in a single class makes it the only point of contact for other classes, which want to use one of its functionalities. Instead of objects communicating amongst themselves directly, the other objects rely on the God object. Because the God object is referenced by so much of the other code, maintenance becomes more difficult than it otherwise would.
Example: A class by name 'ConfigParameters' does all the functions of getting the parameters from the user and setting them in a config file to the appropriate variables and is called in several parts of the program for reading config variables.
Solution: The best way this anti pattern is avoided is by breaking a big problem into many smaller problems (divide and conquer) and solutions are created for each of them. If you are able to solve all of the small problems, you have solved the big problem as a whole. Therefore there is only one object about which an object needs to know everything: itself. And there is only one problem an object needs to solve: its own.
Problem: Overuse of the singleton pattern is referred to as Singletonitis. The major problem with the Singleton pattern is that it creates far too many dependencies within a system. When more and more classes depend on a singleton you start to end up with spaghetti code which is hard to read, even harder to debug and pretty much impossible to unit test.
Example: getInstance() method used to get the instance of the Singleton class.
Solution: A good solution to this problem would be to write loosely coupled, testable and reusable components. Patterns such as Inversion of Control and the containers which implement this provide excellent alternatives to the singleton
Problem: A class suffers from sequential coupling when the consumer of the class must call the methods in a particular sequence or suffer the consequences. This anti-pattern requires an interface that forces you to call multiple methods in the particular order when the interface isn't inherently stateful (like a Collection). In some of the scenarios, the implementation might be storing state in a way that isn't clearly indicated by the interface.
Example: java.util.MessageFormat which uses temporary internal state during single method calls.
Solution: This might be an anti pattern depending upon the context. In some cases, refactoring might help avoiding the expensive analysis on the data.
Problem: The yo-yo problem is an anti-pattern that occurs when a programmer has to read and understand a program whose inheritance graph is so long and complicated that the programmer has to keep flipping between many different class definitions in order to follow the control flow of the program. It often happens in object-oriented programming. The term comes from comparing the bouncing attention of the programmer to the up-down movement of a toy yo-yo.
Example: Any API that has inheritance hierarchy. With methods overridden from the parent class and new methods added to the child class.
Solution: It is proposed to keep the inheritance graph as shallow as possible, in part to avoid this problem. The use of composition instead of inheritance is also strongly preferred, although this still requires that a programmer keep multiple class definitions in mind at once. Techniques such as documenting layers of the inheritance hierarchy can reduce the effect of this problem, as they collect in one place the information that the programmer is required to understand.