n antipattern is a classified bad design; in other words, it is the opposite of a design pattern that suggests good design. Antipatterns present bad solutions in a manner that makes it easy for concerned persons to understand the underlying problems and their consequences. While it is important to know design patterns, I believe it is equally important, if not more so, to understand antipatterns.
Let me justify that position. The world of software revolves around maintenance of applications. Of course, each software product's lifecycle starts with construction, but after the initial roll out, it needs to be maintained. Depending on the development team's skill, the product might have either a good
or a bad
design, with the terms good and bad here applied within a context, because a perfect design can qualify as an antipattern when applied in the wrong context. For example, using a Singleton object might be appropriate in a single-application server environment, but it can actually create issues if not handled properly in a clustered-application server environment. In contrast to a positive design pattern, antipatterns elicit a negative solution or legacy approach (a yesteryear's solution might be an antipattern in today's world) that could be the result of a team member's lack of sufficient information or bad judgment in approaching the design or solving an issue.
The real problem begins only after the product is in production and has entered maintenance mode. A maintenance developer who hasn't worked on the product before might introduce a 'bad design' element into the project. But if such bad practices are codified as antipatterns, they give developers a way to recognize them in advance and avoid the most common pitfalls, just as design patterns codify and provide developers with a way to recognize common useful techniques. Following this logic, an antipattern is a ubiquitous bad design worthy of documenting.
This approach is particularly noteworthy when working with a technology like J2EE. J2EE's initial design philosophy stressed simplicity, but it has morphed into monstrous complexity. In this complex context, both patterns and antipatterns provide a common vocabulary to software managers, architects, designers, and developers alike.
Whether in construction or in maintenance mode, knowledge of antipatterns is imperative for success. Once recognized, developers can refactor these negative patterns to eradicate the bad design, and meliorate the software in general.
This article describes antipatterns from the software architecture and development perspectives. Then it elicits some antipatterns prevalent in the most common layers (user interface, persistence, EJB, etc.) of a J2EE application. The overall goals are to provide background for these antipatterns and suggest solutions to avoid them. To get more detail about any particular pattern, one good source is the book "AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis"
by William J Brown et al.
Table 1 lists three common design, development, and architecture antipatterns described in this article.
Table 1. Common Antipatterns: The table lists three common design, development, and architecture antipatterns.
||Programming to concrete classes rather than interfaces
Coupling logic like logging, security and caching in code
||Reinvent the wheel
The antipatterns listed in this section cut across wide swaths of developer territory.
Programming to Concrete Classes Rather than Interfaces
This is an important design principle, and is often broken. Programming to an interface than a concrete class provides innumerable benefits. You will not be tied into using a specific implementation, and there will be a provision for changing behavior at runtime. The word "interface" implies either a Java interface or an abstract class. As long as you can apply polymorphism, the application's behavior isn't locked into specific code. Note that this principle is not applicable in situations when you know that the behavior is not going to change.
An example of programming to an implementation would be:
Dog animal = new Dog();
In contrast, programming to an interface would be:
Animal animal = getAnimal(Dog.class);
There are two differences here. The second version uses a factory method to obtain an instance of the Dog class dynamically. Also, note that the second version generalizes the bark()
method, which is a Dog-specific implementation of the makeNoise()
method that any animal can implement. The following code shows the getAnimal()
method from an AnimalFactory class along with a Dog class that exemplifies a specific Animal implementation.
if (c == Dog.class)
return new Dog();
// other type tests here
When coding, one basic software concept to keep in mind is that less coupling is generally better. For example, if you code a method to perform a certain task, it should perform only
that task, helping to keep the code clean, readable and maintainable. But inevitably, certain aspects such as logging, security, and caching tend to creep in. There are, fortunately, good ways to avoid this. One such technique, Aspect Oriented Programming (AOP), provides a neat way to achieve this by injecting the aspect's behavior into the application at compile time. For more info, refer to the DevX AOP articles in the related resources section of this article.
Development: The Golden Hammer
Excessive or obsessive use of a technology or pattern leads to the Golden Hammer antipattern. Teams or individuals well versed in a particular technology or software tend to use that knowledge for any other project of similar natureeven when another technology would be more appropriate. They tend to see unfamiliar technology as risky. In addition, it's easier to plan and estimate with a familiar technology. Expanding the knowledge of developers through books, training, and user groups (such as Java User Groups) can be beneficial in avoiding this antipattern.
Software that mishandles simple user inputs is an Input Kludge. A Web site that asks users to logon via an ID and password, for example, should accept as input only characters that are valid for the ID and password. If the site logic rejects invalid input, it is fail-safe in that respect, but if it doesn't, unpredictable results can occur. An Input Kludge is an antipattern that can be easily found by the end user, but not so easily during unit testing by the developer.
You can use a monkey test to detect an input kludge problem. Although it is outside the scope of this article to explain monkey testing methodologies in detail, in short, monkey testing refers to automated testing done randomly without any "typical user" bias.