Why Patterns Exist (and Why They Sometimes Suck)
I wrote a Singleton in 2003. It ran in production for nine years, killed two test suites, and made a junior engineer cry. I am still, quietly, apologizing. Not because the code was wrong — it worked. It kept a single connection pool alive in a C++ process that absolutely needed only one of them. The problem isn't that I used the pattern. The problem is that I reached for it the way someone reaches for a reflex hammer: with my hand already moving before the diagnostic question was finished. I have, in the years since, watched a generation of engineers do the same thing, and I have come to believe that the most important design decision you make is not which pattern to use, but whether to use a pattern at all. This chapter is about that decision. It is also about why the question has become harder, not easier, in the three decades since four guys wrote the book that made "design pattern" a phrase that gets yelled in standups.
The argument I'm going to make, in one breath: design patterns are a vocabulary. They are a way of naming recurring shapes in code so that a team can talk about them without redrawing the diagram every time. The 1994 *Gang of Four* book — Gamma, Helm, Johnson, Vlissides — captured twenty-three such shapes that were already in widespread use in Smalltalk and C++ codebases. It did not invent them. It named them. And somewhere between 1994 and now, the profession got the verbs confused: we started thinking naming something was the same as prescribing it, and prescription became ritual, and ritual became the kind of cargo cult where you draw a UML diagram before you know what the program does. The rest of this book is about how to keep the vocabulary and lose the ritual, and Chapter 1 is where we get the philosophical frame straight. If your brain is already muttering "yes, yes, but just tell me how to write a Strategy" — fine, keep reading, but know that the patterns in Chapter 4 will make more sense once we've agreed on what a pattern is for.
A confession, and the question it leaves behind
Let me be specific about the 2003 incident, because the details are not just color, they are evidence. The system was a fixed-income pricing engine, written in C++, deployed to a Sun E4500 with four CPUs and a sense of institutional self-importance. We had a `MarketDataCache` that, on construction, opened a socket to a Tibco RV daemon, parsed the multicast feed, and built an in-memory order book. There was no good reason to have more than one of these. The feed was a process-scoped resource. Multiple instances would have been a correctness bug, not just a memory waste. So I wrote the canonical C++ Singleton: private constructor, static instance, `getInstance()` accessor, double-checked locking with the then-fashionable `volatile` and memory barrier incantations that were later proved wrong and then proved right again in C++11. It compiled. It ran. It passed review. The lead architect — a patient man named Dmitri who had taught himself C from a K&R paperback — said "I see what you did there" in a tone that was, in retrospect, the vocal equivalent of a wince. I did not register the wince. I was twenty-six. The Singleton shipped.
What the Singleton did, over the next nine years:
- It made unit testing a horror. Every test that needed a fixture involving market data had to reset the global state, which meant tearing down and rebuilding the cache, which meant real network I/O unless you templated the heck out of it. We did not template the heck out of it. Tests got marked `@slow` and ran on a separate CI lane that nobody watched.
- It made parallel development a nightmare. Two engineers working on different features would, transitively, share the cache through the singleton, and a refactor in one branch would silently change the behavior of the other.
- It made ownership of the cache unclear. When the process needed to flush and re-initialize on a config change — which happened every night during the rollover — the code that did so was in `main()`, which knew about the singleton by name, which was in a different translation unit, which included the header that declared it. The dependency graph was a small planet.
- It kept working. This is the part that makes the story dangerous. The Singleton kept working. The pricing engine made money. Nobody ever pointed at the Singleton and said "this is why we missed a deadline." The damage was diffuse, attributed to "the legacy" and "the platform" and "the test environment" — never to the choice of pattern.
I have, since then, written two more Singletons, both for the same reason: the process genuinely needed one of something, and the alternative was passing a pointer through eleven layers of function arguments. I do not feel guilty about those. I feel guilty about the 2003 version, because in 2003 I did not know enough to ask whether the Singleton was the right tool or just the first tool that fit my hand. That is the disease this chapter is named after. The disease has a real name, but I'll get to that in a minute.
The question every working engineer eventually asks — usually at 2 a.m. before a release, or at 10 a.m. during a design review when a colleague is drawing a hexagonal diagram on a whiteboard — is this: are design patterns timeless wisdom, or are they a 1994 artifact we keep reverencing out of habit? The honest answer, which I will defend for the rest of this chapter, is: they are a vocabulary that was useful in 1994, is still useful in 2026, and has been corrupted by a generation of engineers who learned the words before they learned the language. Patterns are tools. Tools are not wisdom. The wisdom is in the choice of tool, and the choice of tool is a question that can only be answered by the codebase in front of you, not by the catalog on the shelf.
The pre-history: where the word came from
To understand what the GoF book is, you have to know what it isn't, and to know what it isn't, you have to know what was on the shelf before it. The phrase "design pattern" did not originate in computer science. It originated in architecture, in the work of a man named Christopher Alexander, who in 1977 published *A Pattern Language*, a book that probably changed more about how software is discussed than any single computing text except maybe *The Mythical Man-Month*. Alexander was a practicing architect — buildings, not software — and he was frustrated by the way modern buildings all looked the same. Not because the engineers were bad, but because they were solving the same problems in the same ways without ever writing down what they were doing. His insight was radical in its simplicity: there are recurring problems in the built environment, and the solutions to those problems, when they are good, have a recognizable shape. If you can name the shape, you can talk about it. If you can talk about it, you can teach it. If you can teach it, you can choose it deliberately instead of reaching for it by accident.
*A Pattern Language* is structured as a catalogue of 253 patterns, each with a name, a problem statement, a sketch of the solution, and a discussion of consequences. The pattern names are evocative: "Light on Two Sides of Every Room," "Six-Foot Balcony," "Window Place," "Building Edge." A pattern is not a recipe. It is a description of a relationship between a problem and a solution, observed across many specific instances, abstracted just enough to be portable. Alexander was emphatic that patterns are discovered, not invented. They are out there in the world. The pattern language is just a map.
The software world encountered Alexander in the late 1980s, mostly through the work of Ward Cunningham and Kent Beck, who were building Smalltalk systems at Tektronix and felt that the architecture metaphor fit. The OOPSLA conference — the ACM conference on Object-Oriented Programming, Systems, Languages, and Applications — became the venue where this idea got chewed on. In 1987, Cunningham and