The term “anti-pattern” is a derogatory term used to disparage software design approaches that a given developer, or group of developers may not like. The term started its life as a useful way to describe approaches that generally lead to bad outcomes, or for approaches designed to solve problems that already have a proven solution. While some approaches often do lead to bad outcomes, there are very few problems simple enough where a one size fits all solution is adequate for all scenarios. This article is part of a series on Critical Thinking in Software Development and talks about how the term is being misused.
According to Wikipedia, a software design pattern is:
a general, reusable solution to a commonly occurring problem within a given context in software design […] It is a description or template for how to solve a problem that can be used in many different situations. Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.
The first part of this definition is perfectly reasonable. If some problem has been solved, and that solution has proven to be effective time and time again, it’s reasonable to consider it as a template for solving similar problems again in future. However, the definition extends further and says that “patterns are formalized best practices”. To qualify for the term “pattern”, an approach is not worthy until someone or some group has proven through some formal process that this approach is superior to all others, and qualifies as “best practice”. An approach that earns the title of “pattern” not only becomes one tool in the toolbox, it becomes dogma. Everything that runs contrary to a given pattern becomes an “anti-pattern”.
must be at least two key elements present to formally distinguish an actual anti-pattern from a simple bad habit, bad practice, or bad idea:
- A commonly used process, structure, or pattern of action that despite initially appearing to be an appropriate and effective response to a problem, has more bad consequences than good ones.
- Another solution exists that is documented, repeatable, and proven to be effective.
This definition sounds reasonable and useful. However, when taken on its own the second part of the definition implies that because an approach has proven to be effective at solving a problem, it is pointless to attempt to solve the problem in any other way. This is where the issue of misusing the term becomes a problem. Approaches are routinely singled out as anti-patterns simply because another pattern exists when no case has been made that the approach has been found to have bad consequences in the past. It often used as the only argument against a particular approach with no explanation necessary for why the approach will lead to bad consequences.
The existence of a pattern for solving some problem does not mean that other approaches are inherently incorrect, or valueless. The phrase “there is more than one way to skin a cat” is a truism that we all intuitively understand. While there are some approaches that tend to lead to bad results, and some that tend to lead to good results, there is no correct or incorrect approach for all scenarios.
Evolution of Ideas
Engineering ideas evolve over time. What may be impossible today may be possible and recommended tomorrow. What was possible yesterday may not be possible or desirable today. Moreover, problems are not isolated. When an engineer is attempting to solve a problem, there is always more than one thing to consider. Lets take transportation as an analogy.
Before horses were domesticated, people must have assumed that walking or running from place to place was the most efficient way to travel. People must have had the fixed idea that traveling long distances quickly was impossible. When horses were domesticated, it was discovered that people could travel over longer distances in a shorter period of time. With the use of carts and maritime travel they could also move more food and supplies over larger distances.
Later, trains, automobiles, and airplanes were invented. Imagine if it had been declared that trains were the only valid pattern for solving the problem of transportation. Imagine that the combustion engine had been declared an anti-pattern because of its absurd wastage of fuel. In hindsight we can see how destructive the combustion engine has been for the environment, but the automobile has emancipated people from the tyranny of distance, and trucks have allowed goods to flow freely across borders and supply remote communities with much needed items.
If one asks the question today “Which form of transport is best?”, there is no single answer. Horse riding solved the problem of traveling long distances quickly, but there were many inefficiencies – much like the automobile. Many other forms of transport were invented, and yet, rail and shipping remain the most environmentally friendly forms of transport. No single design pattern for transportation was correct, and no one approach used today is an anti-pattern. A square wheel could easily qualify as a good use of the term anti-pattern because there is no scenario in which a square wheel is a good design pattern, but air travel is not an anti-pattern. The invention of the automobile as a form of transport did not relegate airplanes to the anti-pattern bucket. But, at the same time, airplanes do not make automobiles obsolete either.
Ideas, practices, principles, approaches and so on evolve over time. Declaring one of these as correct and all others to be incorrect is an oversimplification, and a logical fallacy. Using the words pattern and anti-pattern as synonyms for correct or incorrect ignore reality and and further cements software development dogma.
The importance of prototyping needs to be considered here. Developers bring with them years of received knowledge from universities, blogs, other developers and so on. It’s easy to habitually rely on preconceived ideas and practices, but prototyping often proves to be the best way to road test an approach. If a given pattern is the best way to solve a problem, then prototyping it, and comparing it with other prototypes will highlight its benefits. The marshmallow challenge highlights how children tend to approach problems by quickly experimenting without preconceived ideas, quickly reevaluate ideas, and learn from past mistakes.
Every approach needs to be evaluated on its merits for the use in a specific scenario, and trialing multiple approaches to gain objective insights in to what works best in a given scenario is always going to be superior to blindly following received knowledge. When “anti-patterns” are rejected as being incorrect, prototyping is seen as unnecessary and valuable lines of exploration are often avoided. It would be a mistake to think that just because a problem has been solved with a given pattern, that every other similar problem can be solved with the same pattern. Only trialing an approach can demystify potential benefits and costs that an approach may yield.
Points To Consider
- The existence of a pattern for solving a problem does not mean the absence of valid alternative solutions. In other words, categorizing an approach as an anti-pattern is not a valid argument against an approach
- Some accepted patterns have been proven to be bad
- There is no authority that a developer can turn to on all decision making
- Developers may need to get burned by approaches a few times to understand why an approach is generally bad
- The best way to evaluate an approaches is to prototype and compare them in your scenario
- Following established patterns is usually a good idea
- Being guided by validated studies is likely to enhance the chance of project success
- Reinventing the wheel is risky and time consuming
- Following patterns that other developers can recognize and understand is likely to save time and enhance the chance of project success
- Approaches that have been studied and proven to reduce the chance of success should be viewed unfavorably
My general contention is that the field of software development is often dominated by people or groups considered to be authorities, that dogma is pervasive, and that developers are often socialized out of critical thinking. Learning lessons based on experience rather than rote memorization of principles is important. When an approach is categorized as an anti-pattern, there is no further explanation necessary for critical thinking on the topic, and other software developers feel they can safely ignore the approach. This creates a toxic culture in the field of software development where useful approaches are often overlooked. A positive path forward is to keep an open mind, continue evaluating knowledge based experience and experimentation, and to learn not to shoot down other based on received knowledge. Most importantly, stop categorizing people’s ideas as anti-patterns when you simply disagree with them.
Note: This article contains edits