On a cold day in Eastern Tennessee, my kayak is perched precariously atop a 16-foot waterfall known as State Line Falls. This rapid has a nasty reputation for smashing boats and people. From the top, there is no clue of the danger that lurks around the bend, but I know. The guidebook description has been on my mind every waking hour for several days. Five truck-sized boulders guard four slots. I will see the entire waterfall only seconds before I go over it. Three of the four slots are reputed to be too violent and dangerous for your mother-in-law. The river rips through the fourth "friendly" slot, picks up speed, and crashes onto the jagged rocks. I am a programmer by trade, a father of two, and a kayaker of intermediate skill. I have no business going over a Class V waterfall described in guidebooks as "marginal." What the heck am I doing here?
The programmer in me has asked the same question many times. As I prepare to attack an unfamiliar problem with mounting schedule pressures and dire consequences for failure, I've been on the edge of a similar cliff more times than I care to mention. In this article, I'll discuss a tool that can help you navigate a programmer's turbulence: the antipattern. I'll also point out ways that antipatterns can complement your design pattern study. If you're a frequent visitor to developerWorks, you've seen many design patterns introduced, and witnessed arguments of their inherent value. However, while Eric Allen's articles on bug patterns (see Resources) give you a hint of their utility, you probably don't yet have the same appreciation for antipatterns. You're not alone. Developers have published insightful books and articles on design patterns for years, but the same community has been conspicuously less forthcoming on antipatterns. My goal in this article is to show you that antipatterns are a necessary and complementary companion to design patterns.
Repeat successful strategies with design patterns
As I look over the run above State Line Falls, I reflect on what I know. From talking to others, I know that all of the successful runs go down the right side of the third slot, and that I must run the rapid with speed to avoid the rocks under the shallow water beneath the falls. With this knowledge to steel my confidence, I leave the protected safety of the eddy, and enter the main current.
Though I didn't think about it in these terms, I was using design patterns. I based my strategy on the successful runs of similar boaters who had run before me. Design patterns gave me the confidence to run a rapid that would otherwise be beyond my skill level. I frequently apply the same principles to programming and architecture; you can learn from watching the repeated successful results of a strategy to solve a given problem. With design patterns, the results are positive. You can tap your own experience, watch a mentor, or read about what the experts do.
Many of the most important advances in our programming craft have come from design patterns. The Model-View-Controller pattern taught us to effectively partition our code along a well-defined boundary between the user interface and model. The Publish-Subscribe design pattern taught us how to manage events without broadcasting them. Other design patterns have had a tremendous impact on various Java frameworks: the proxy EJB interfaces for remote communications, the collection classes, the Swing framework, and many others.
I am a tremendous fan of building a repeatable process. From this perspective, design patterns have much to offer. Design patterns force you to think about slicing your problems into discrete sub-problems, some of which may leverage repeatable solutions. They also force you to think about how you formally represent and communicate your design knowledge, so that others can leverage your work.
But design patterns are not enough. If you think of a programming problem as terrain that you have to traverse, a design pattern is at best a partial map. After all, if a perfect solution already existed that met your needs, you'd probably be buying rather than building. Further, as the supporting software evolves, the infrastructure -- the existing roads on our map -- change rapidly. Partial maps can navigate you through some of the danger, but not all of it. You're going to have to venture off your map to reach your destination. So, what do you do when you get lost?
Avoid painful traps with antipatterns
As I line up for my run, the current pushes me left. Kayakers must intimately know the danger spots in advanced rapids, and I have done my homework. I know that some boaters before me drifted left and crashed, and I have discussed and mentally rehearsed ways to correct for this problem. So prepared, I use an aggressive draw stroke to bring me back in line. I've now got a fighting chance to get through this one in one piece.
Here's how to view this as an antipattern: I've started with a difficult problem. I choose a plan based on other successful solutions: my design pattern. My plan goes wrong, but I am prepared to respond through analyzing other troubled runs through my rapid: I am using antipatterns. Because I'm prepared, I recognize the problem, and adjust my approach to get back on track: I am refactoring. In advanced kayaking and programming, learning from your own mistakes is valuable but painful. I would much rather learn from the mistakes of others. With this approach, I am able to attack problems that would normally be far beyond my abilities.
The authors of Antipatterns: Refactoring Software, Architectures, and Projects in Crisis (see Resources) define antipatterns like this:
An antipattern is a literary form that describes a commonly occurring solution to a problem that generates decidedly negative consequences.
The key phrases here are:
-
Literary form: Antipatterns are descriptions of problems, rather than code. This is important, because we can quickly and efficiently deliver a message, and our clients can quickly understand.
-
Commonly occurring: If it isn't a pattern, then it isn't an antipattern. You must establish several different instances of poor behavior, preferably in different contexts, for a bug to rise to the level of an antipattern.
- Negative consequences: The design has to have an observable, negative impact.
The most famous antipattern, Y2K, shows us the peril and the promise of this exciting new field. Recall that hundreds of thousands of developers coded dates with two digits instead of four, and incorrectly compared those digits causing millions of bugs. Many prominent researchers predicted widespread disaster, but through intensive study of the problem, new identification and refactoring techniques repaired code so efficiently that few ever experienced problems on the predicted scale. Antipatterns, like design patterns, are recurring solutions. The difference is that they have negative consequences. When you document an antipattern, you will want to capture at least these elements:
-
Name: Sometimes, an antipattern will already have one or more informal names, given from a development community. Other times, you'll want to choose one. It should be descriptive and simple.
-
Problem: The problem describes the antipattern's flawed solution, and also the motivating factors that steer developers toward the flawed solution. This description teaches others how to find the problem.
- Refactored solution: Antipatterns are useful to the extent that they can help us extricate ourselves from traps, or avoid them entirely. The refactored solution is a guide that teaches others how to fix the problem.
Other industries use antipatterns with success
Many other industries -- most notably, manufacturing -- use antipatterns in some form, usually in combination with design patterns. Current manufacturers copy successful process improvements from others with reckless abandon. For example, take the Just-in-Time "design pattern." Just-in-Time manufacturing is a process allowing reduced inventory and rapid correction for quality problems, improving quality. Each successive step in a process uses assemblies delivered just in time from the previous step. All of the major automotive manufacturers now use this technique. Manufacturers also adopt other design patterns for assembly organization, testing and data collection. The best manufacturers do not stop there. They also recognize the need for finding systemic process failures. Programs like Zero Defects and Quality Circles let blue-collar plant floor workers periodically take some time to discuss systemic process problems, and how best to prevent them. The average program saves an employer many more times what it costs to maintain. Other examples of antipatterns in industry include:
- The health industry, where researchers find and publish bad dietary habits, and good doctors use that information to teach patients to change the root causes of poor health, not just the symptoms.
- Law enforcement, where officers work with communities to identify and prevent the root causes of crime in troubled neighborhoods. These programs can significantly decrease drug use and violent crime.
- The publishing industry, where after a decade of neglect, the most successful publishers once again work in close partnership with authors. This partnership helps authors identify and correct bad writing habits, producing better books. The most successful technical publisher uses this approach, and others are starting to copy it.
Examples of antipatterns in the Java language
If antipatterns are successful in other industries, can programmers benefit from them as well? I believe that programmers have more to gain. To succeed as a programmer, you simply have to quickly recognize common traps. Software development uses an incredibly diverse set of tools, languages, methods, and strategies. Think back to our map analogy. Problems vary slightly from one situation to the next. You will need to be able to generalize knowledge and transfer it between circumstances to succeed. While design patterns tend to target very specific problem domains, antipatterns can be more general. In truth, many of the mistakes that you're likely to make have been made before. Antipatterns help you recognize more of them earlier in the development cycle. If you are like most programmers, dedicating a little time to understanding the traps in the current landscape can save you a tremendous amount of time and effort. The evolution of the Java language shows us many examples of mistakes that we borrowed from other programming generations:
- Early implementations of EJB entity beans were dog slow, partly because the communication costs were too high.
After a period of time, people started to recognize that one significant problem was round-tripping. We eventually learned to refactor those solutions with remedies like facades. (See The Round-Tripping antipattern sidebar for details.) Other developers stepped on this land mine long before EJB components ever existed. Early databases on the personal computer struggled with performance until administrators learned to use stored procedures to consolidate many database communications into one. Early distributed systems developers found the same problem, and published the Facade solution.
- Another example of a common Java antipattern is the Magic Servlet. This very basic antipattern, detailed in The Magic Servlet antipattern sidebar, has trapped many of my relatively advanced customers. In it, a single servlet processes view, model and controller logic. Such a design makes maintenance all but impossible, because whenever the view changes, you must change the model logic, and vice versa. The Magic Servlet, too, has roots predating the Java language. The most common examples of this problem actually occur with Visual Basic, where it is common for programmers to attach 10K script to a single control, like a pushbutton.
These problems just scratch the surface. With each new frontier, Java developers rediscover old mistakes with some regularity. If we study the traps with intent to steer clear, surely we save ourselves some pain.
Hopefully, I've convinced you that antipatterns are worth your attention. What can you do to incorporate them into your everyday routine? Figure 1 shows the rough steps of a process to help you identify and solve antipatterns. I discuss these in greater detail in my book, Bitter Java (see Resources).
Figure 1. Steps in a basic antipatterns process

-
Identify a problem. In Java programming, the problem might be a bug, a performance problem, a class that is difficult to maintain, or a growing memory footprint.
-
Establish a pattern. If you're a student of software engineering, then you know that the cost of fixing a bug grows exponentially as you get deeper into the development cycle. When you establish a pattern of problems, then you give yourself the opportunity to identify and fix more problems earlier in the development cycle, multiplying your gains. The key to moving up this value chain is to establish a pattern, and then to act on the antipattern as broadly as possible.
-
Refactor the code. With this step, you refactor the code that causes the problem. This step is a simple bug fix, applied to all of the problem instances that you've identified so far. You should take care to do a complete fix instead of a quick patch, and you should add documentation if the bug is likely to occur in the same place. You'll also want to document your steps so that you can distribute the solution to others.
-
Propagate the solution. Here you make sure that others that encounter the bug know how to fix it, and others that may encounter the trap know to avoid it. Publishing antipatterns can spread the benefits even more broadly.
- Fix the process. Here you build a protective barrier against the antipattern. A fix can take many different forms. Improving test cases can quickly identify regression. Fixing an everyday process or communication channels can prevent problems before they start. Beefing up coding standards can all but eliminate some types of coding errors, like bugs related to brace or comment placement.
These steps take the approach of going from the specific to the general. You find a bug, establish a pattern, fix the bug, and fix the process. Incorporating some of these steps into your daily routine can make you a better programmer. But, don't stop there. Work your way up the value chain by using your antipattern knowledge to fix your process and make programmers throughout your company better. Publish your antipatterns and improve programmers that you don't even know. If you're a programmer and a fan of design patterns, I am sure that you will find that antipatterns have much to offer.
The rest of my run is anticlimactic: I sweep, free-fall, and land with a soft "poof" in the foam. I paddle the rest of the day with a silly grin, unable or unwilling to remove it from my face, until I reach the safety of the cars waiting down below.
-
Bitter Java (the book) should be hitting the bookshelves about the time that this article is published. You'll find more background information about antipatterns, but also information about memory management, caching, EJB components, coding conventions, performance analysis, and more.
- The IBM redbook
Design and Implement Servlets, EJBs and JSPs for WebSphere
, while slightly dated, has outstanding information about the modified Model-View-Controller architecture used in the Magic Servlet sidebar.
- "Struts, an open-source MVC implementation" by Malcolm Davis (developerWorks, February 2001) introduces this popular framework and explores how it can help you control change in your Web project and promote specialization.
-
Antipatterns: Refactoring Software, Architectures, and Projects in Crisis
by W.J. Brown, Malveau, W.H. Brown, McCormick, and Mowbray (John Wiley & Sons, 1998) is the book that started the antipattern ball rolling. It provides good information about templates that you can use to capture antipatterns.
- Eric Allen's popular column on developerWorks,
Diagnosing Java Code
, captures the spirit of antipatterns -- in the form of bug patterns -- but at a lower level.
- If you're new to design patterns, David Gallardo's tutorial "Java design patterns 101" (developerWorks, January 2002) explains why patterns are useful and important for object-oriented design and development.
- See design patterns in action on the IBM Patterns for e-business site.
- Find hundreds of other Java-related articles on the developerWorks Java zone.

Bruce Tate is an independent consultant and author. He worked at IBM for 12 years in a variety of roles, including leading a Java proof-of-concept team. Bruce was recruited from IBM to run the solutions development organization for an Austin startup, and later left that role to build his own business: J2Life, LLC. He is the author of three books, including Bitter Java , a book on Java antipatterns. Contact Bruce at bruce.tate@j2life.com.





