As engineers, we may run into situations when we are on a deadline to deliver a solution or where code gets included as a series of patches without a code review. The code in such cases may not always be well thought out and may propagate what we call anti-patterns. This chapter describes what anti-patterns are and why it is essential to understand and identify them. We also look at some typical anti-patterns in JavaScript.
If a pattern represents a best practice, an anti-pattern represents the lesson learned when a proposed pattern goes wrong. Inspired by the GoF’s book Design Patterns, Andrew Koenig first coined the term anti-pattern in 1995 in his article in the Journal of Object-Oriented Programming, Volume 8. He described anti-patterns as:
An antipattern is just like a pattern, except that instead of a solution, it gives something that looks superficially like a solution but isn’t one.
He presented two notions of anti-patterns. Anti-patterns:
Describe a bad solution to a particular problem that resulted in an unfavorable situation occurring
Describe how to get out of the said situation and go to a good solution
On this topic, Alexander writes about the difficulties in achieving a good balance between good design structure and good context:
These notes are about the process of design; the process of inventing physical things which display a new physical order, organization, form, in response to function. … Every design problem begins with an effort to achieve fitness between two entities: the form in question and its context. The form is the solution to the problem; the context defines the problem.
Understanding anti-patterns is as essential as being aware of design patterns. Let us qualify the reason behind this. When creating an application, a project’s lifecycle begins with construction. At this stage, you are likely to choose from the available good design patterns as you see fit. However, after the initial release, it needs to be maintained.
Maintenance of an application already in production can be particularly challenging. Developers who haven’t worked on the application before may accidentally introduce a bad design into the project. If these bad practices have already been identified as anti-patterns, developers will recognize them in advance and avoid the known common mistakes. This is similar to how knowledge of design patterns allows us to recognize areas where we could apply known and helpful standard techniques.
The quality of the solution as it evolves will either be good or bad, depending on the skill level and time the team has invested in it. Here, good and bad are considered in context—a “perfect” design may qualify as an anti-pattern if applied in the wrong context.
To summarize, an anti-pattern is a bad design that is worthy of documenting.
Developers sometimes knowingly opt for shortcuts and temporary solutions to expedite code deliveries. These tend to become permanent and accumulate as technical debt that is essentially made up of anti-patterns. JavaScript is a weakly typed or untyped language that makes taking certain shortcuts easier. Following are some examples of anti-patterns that you might come across in JavaScript:
Polluting the global namespace by defining numerous variables in the global context.
Passing strings rather than functions to either setTimeout
or setInterval
, as this triggers the use of eval()
internally.
Modifying the Object
class prototype (this is a particularly bad anti-pattern).
Using JavaScript in an inline form, as this is inflexible.
The use of document.write
where native Document Object Model (DOM) alternatives such as document.createElement
are more appropriate. document.write
has been grossly misused over the years and has quite a few disadvantages. If it’s executed after the page has been loaded, it can overwrite the page we’re on, which makes document.createElement
a far better choice. Visit this link for a live example of this in action. It also doesn’t work with XHTML, which is another reason opting for more DOM-friendly methods such as
document.createElement
is favorable.
Knowledge of anti-patterns is critical for success. Once we learn to recognize such anti-patterns, we can refactor our code to negate them so that the overall quality of our solutions improves instantly.
This chapter covered patterns that could cause problems known as anti-patterns and examples of JavaScript anti-patterns. Before we cover JavaScript design patterns in detail, we must touch upon some critical modern JavaScript concepts that will prove relevant to our discussion on patterns. This is the subject of the next chapter, which introduces modern JavaScript features and syntax.