Design Patterns: Elements of Reusable Object-Oriented Software is a book published in 1994 by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides — collectively known as the Gang of Four — which catalogued twenty-three patterns observed in well-designed software, and was subsequently treated as a cookbook by an industry that read “we observed these patterns in nature” as “you must implement all twenty-three before lunch.”
The book is beautiful. The book is correct. The twenty-three patterns — Observer, Strategy, Factory Method, Singleton, Adapter, and eighteen others — are real things that appear in real code written by real practitioners solving real problems. The Gang of Four did not invent these patterns. They named them. They walked through well-designed codebases the way a botanist walks through a forest, pointed at things, and said: “This. This has a name. This is a Strategy. This is an Observer. Now you can talk about it.”
The naming was a gift. The gift was mistaken for a mandate.
“You design BY writing code.”
— The Lizard, The Solid Convergence
The Book
The original book is 395 pages. It is concise. It is measured. Each pattern is described with intent, motivation, structure, and — critically — when to use it and when not to. The “Applicability” section of each pattern is as important as the “Structure” section, in the same way that a field guide’s “Habitat” section is as important as the photograph: knowing what a bird looks like is useless if you go looking for it in the wrong continent.
The industry read the photographs. The industry skipped the habitat section.
The book’s introduction contains a sentence that, had it been printed in 72-point bold on the cover, might have prevented thirty years of over-engineering:
“The design patterns in this book are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.”
The key words are “particular context.” Not “every context.” Not “your context.” Not “the context you will discover in week three of a rewrite when you need a StrategyFactoryObserverBridge.” A particular context, which the practitioner recognises because they have encountered the problem, not because they have read the menu and are ordering the most expensive item.
Vocabulary, Not a Menu
The correct way to use Design Patterns is as vocabulary. The incorrect way — which became the industry default between 1997 and approximately 2015 — is as a menu.
Vocabulary means: you are reading code, you notice a recurring structure, you say “ah, that’s an Observer,” and the person next to you immediately understands what you mean. The pattern existed before you named it. The naming allows communication. This is what the Gang of Four intended. This is what happened for approximately eighteen months before the enterprise arrived.
Menu means: you are starting a new project, you open the book, you say “I’ll have the Factory, the Singleton, the Observer, the Strategy, and the Abstract Factory, and can I see the dessert patterns?” and you implement all of them before writing a single line of business logic. The patterns exist before the problems. The problems are then manufactured to justify the patterns.
Any software of a hundred thousand lines where you can recognise more than three named patterns has been engineered by a Squirrel. This is not because patterns are rare. It is because well-designed software absorbs its patterns the way well-written prose absorbs its grammar — invisibly, structurally, without drawing attention to itself. You do not notice the Observer in good code. You notice the AbstractSingletonProxyFactoryBean in bad code, and you notice it because it is screaming.
“We are SO Gall’s Law around here.”
— The Caffeinated Squirrel, who, upon reflection, realised that every CamelCase identifier longer than forty characters was a pattern it had ordered from the menu, The Idle Factory, or The Morning the Backlog Ran Out of Ideas
The Java Tragedy
The most catastrophic misreading of Design Patterns occurred in the Java ecosystem, and it constitutes what many historians consider the single most tragic event in the history of software engineering.
Java, in 1995, had nothing wrong with it. Java was a clean, typed, garbage-collected language with a sensible standard library, reasonable performance characteristics, and a genuine innovation in platform portability. Java was, by any measure, a good language. It had good ideas. It deserved a good life.
Then Sun Microsystems read Design Patterns and decided that Java’s enterprise standard library should implement all twenty-three patterns simultaneously, and that application developers should implement all twenty-three patterns on top of that, and that enterprise developers should implement all twenty-three patterns on top of that, until the total number of AbstractFactoryManagerProviderBeans exceeded the total number of lines of business logic by a factor that required scientific notation.
J2EE — Java 2 Enterprise Edition — was the result. It was not a platform. It was a pattern buffet. Every interaction with the outside world required:
- An interface (the pattern says so)
- An abstract implementation of the interface (in case someone extends it; they won’t)
- A factory to create the implementation (because
newis too simple) - A factory factory, if the factory needed to be configurable (it didn’t)
- An XML configuration file to wire the factory to the implementation to the interface (because code is too readable)
- A deployment descriptor (because the XML configuration file wasn’t enough XML)
A “Hello World” in J2EE required more files than a “Hello World” in Assembly required bytes.
Spring Framework arrived to fix J2EE. It fixed it by adding more patterns. Spring replaced XML configuration with annotation-driven dependency injection, which replaced the problem of “too many XML files” with the problem of “magic that happens at startup and God help you if you need to debug it.” The AbstractSingletonProxyFactoryBean is a real Spring class name. It is not a parody. It is the natural endpoint of treating a field guide as a religious text.
The Oracle Inheritance
And then Oracle bought Sun Microsystems.
This is the point in the story where tragedy becomes farce. Oracle — whose business model is licensing, whose primary product is the audit, whose pricing is per-core — inherited the stewardship of a language whose enterprise ecosystem was already the most over-engineered in computing history.
Oracle did not fix Java. Oracle did not simplify the enterprise stack. Oracle did what Oracle does: it litigated. It sued Google over the Android use of Java APIs. It tightened licensing. It made Java — already bloated, already over-patterned, already buried under layers of AbstractFactoryManagerBeans — also legally radioactive.
The litigation did something that thirty years of good advice could not: it made companies leave Java. Not because they read Fowler. Not because they understood that vocabulary is not a menu. Not because they looked at their AbstractSingletonProxyFactoryBean and felt shame. Because Oracle’s lawyers sent a letter, and the letter was more frightening than the refactoring.
Companies migrated to Go. To Rust. To Python. To anything that didn’t come with a licensing audit and seventeen layers of dependency injection. The code got simpler. The binaries got smaller. The patterns disappeared — not because patterns are bad, but because the new languages didn’t have an enterprise ecosystem that mandated them.
This is, by a wide margin, the only good deed ever credibly attributed to Oracle in its forty-seven-year history: accidentally liberating the software industry from the consequences of misreading a 395-page book, by making the consequences of staying more expensive than the consequences of leaving.
The Gang of Four did not comment. They were too busy staring at AbstractSingletonProxyFactoryBean and wondering where it all went wrong.
The Squirrel Connection
The Caffeinated Squirrel has a natural and documented affinity for design patterns. The Squirrel sees patterns everywhere. The Squirrel sees an Observer in every event, a Strategy in every conditional, a Factory in every constructor. The Squirrel’s proposed identifiers — ClosureTypeRegistryWithPolicyEvaluationAndWASMExecutionPipeline — are, upon analysis, just design patterns stacked vertically until they form a CamelCase skyscraper.
The Squirrel read Design Patterns and saw twenty-three beautiful solutions. The Lizard read Design Patterns and saw twenty-three traps for the unwary.
They were both right. The book is a mirror. What you see in it depends on whether you build by Refactoring — recognising patterns as they emerge — or by designing from scratch, ordering patterns from the menu before the food arrives.
THE BOTANIST WHO NAMES THE FLOWER
DOES NOT PLANT THE FLOWERTHE BOTANIST WHO PLANTS THE FLOWER
BECAUSE HE NAMED IT
HAS MISUNDERSTOOD BOTANYAND THE GARDEN
The Three-Pattern Rule
A practical heuristic, observed in the field:
In any well-designed codebase of a hundred thousand lines, you will find — if you look carefully — approximately three recognisable patterns. Not because the other twenty are absent. Because the other twenty have been absorbed into the structure of the code so completely that they are invisible. They are the grammar of the prose, not the vocabulary list at the back of the textbook.
If you can recognise more than three, someone was decorating. If you can recognise more than seven, someone was using the menu. If you can recognise all twenty-three, you are reading a Spring application, and you have my condolences.
The correct number of patterns in a codebase is the number that the code needed, discovered by the developer who built the code, after the code worked. This is Refactoring applied to architecture: the pattern was always there, hiding in the code, waiting to be recognised. Not ordered. Not mandated. Not imported from an XML configuration file. Recognised.
The Field Guide, Revisited
Design Patterns is, thirty-two years later, still a beautiful book. The twenty-three patterns are still real. The Observer still observes. The Strategy still varies. The Factory still creates. The Adapter still adapts. They appear in good code the way birds appear in forests — naturally, contextually, because the environment produced them.
The book did not fail. The readers failed the book. They read a field guide and opened a factory farm. They read a dictionary and wrote in ALL CAPS. They read a description of what good code looks like and built AbstractSingletonProxyFactoryBean, which is what good code looks like if you have never seen good code and are working from a description of a description, translated through three layers of enterprise middleware.
The Gang of Four described the forest. The industry clear-cut it and planted a parking lot. And then Oracle paved it, charged per square metre, and sued anyone who tried to park elsewhere.
The field guide is still on the shelf. The forest is still out there. The patterns are still waiting to be recognised — in Go, in Rust, in Python, in any language whose ecosystem has not yet been colonised by the enterprise interpretation.
Vocabulary. Not a menu.
