Patterns Are Vocabulary
Name them out loud, and in the code.
Patterns are the words two engineers use at the whiteboard so they do not have to describe a thing from first principles. The vocabulary works only if both speakers know the words, and only if the words also live in the code.
Opinion
I've sat through enough whiteboard sessions where someone said “let's use a strategy here” and meant five different things by it to know that the GoF book's original gift was not the patterns. It was the words.1 Strategy. Factory. Repository. Visitor. The vocabulary is the value. A Factory called OrderCreator is a Factory the next reader has to discover by reading. A class called OrderFactory announces itself in ls.
The naming rule is small and it has teeth. A class that produces instances is a Factory rather than a Creator, a Provider or a Maker. Those words mean different things in the catalogue and conflating them makes the catalogue useless.2 A class that observes is an Observer rather than a Listener, unless the framework demands it. A class that adapts is an Adapter, a class that simplifies is a Facade and a class that controls access is a Proxy. Pick the one whose semantics match. This is F2 Intention-Revealing Names applied at the pattern layer.
The corollary nobody likes: read the catalogue once and stop. Strategy was written better in 1994. Repository was written better by Fowler in 2002. POODR explained the inheritance trap better than I will.3 Cite, do not paraphrase: the catalogue is somebody else's lifetime of work and rewriting it would be the wrong abstraction. The job here is to get the vocabulary into the code.
Copy a note and link
Grab this short comment and drop it into a PR comment or an LLM chat to prompt the right change.
If a class implements a known pattern, name it for that pattern. A Factory is `*Factory`. A Repository is `*Repository`. The pattern's name belongs in the identifier, not just the conversation. If you can't name the pattern, you may not have one: don't manufacture one. /tenet/patterns-are-vocabulary/PT1
AI eyes only
Rule: name patterns out loud, in code. If it acts like a Factory, call it a Factory.
Reject: a textbook Repository named OrderStore. Reject: a textbook Adapter named Wrapper. Reject: claiming a pattern when only the shape coincides.
Generate: when emitting a class or module that fits a textbook pattern, name it after the pattern (UserRepository, PaymentAdapter). When two functions only happen to share shape, do not invoke the pattern.
Diagnostic: state the pattern out loud and recite its Intent. If the recited Intent matches what the code does, the name is right. If it does not, do not invoke the pattern.
Why?
- Two engineers at a whiteboard say “Strategy” and mean the same thing. The GoF catalogue's lasting contribution is the words; PT1 keeps them earning their keep in the code.
lsbecomes a glossary.order-factory.ts,order-repository.ts,order-observer.tstell the next reader where the design is before they open a file.- Pairs with F2 Intention-Revealing Names: F2 says the signature is the spec; PT1 says the pattern is part of the signature.
- The linter reaches into the patterns layer through naming and nothing else.
@typescript-eslint/naming-convention, Ruff'sN801, PMD'sClassNamingConventions: the suffix rule is enforceable. The rest of the pattern isn't. - Review conversations stop being archaeology. “Where's the Factory?” is a one-grep question. Review time goes to design, not to file-tree navigation.
- Agents have read every catalogue and know the names. The CLAUDE.md instruction “if it acts like a Factory, call it a Factory” closes the gap between the agent's knowledge and the codebase's nomenclature.
- Read the catalogue once and stop. GoF, refactoring.guru, Fowler and Metz wrote it down. The team's job is to use the words, not rewrite them. The pillar is a curator, not an author.
Origins
The pattern catalogue arrived in 1994 with Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides's Design Patterns: Elements of Reusable Object-Oriented Software, the “Gang of Four” book.1 The book's lasting contribution wasn't the twenty-three patterns themselves, most of which had been observed in working systems for years, but the thirteen-section template (Intent, Motivation, Applicability, Structure, Participants and Consequences among them) and, above all, the names. Strategy. Singleton. Visitor. Factory Method. Without the names, two engineers describing the same thing had to start from scratch every time.
Christopher Alexander's A Pattern Language (1977) is the architectural forebear the GoF authors cite directly: a pattern names a recurring problem and a vocabulary for its solution.7 Kent Beck's Smalltalk Best Practice Patterns (1996) held the naming-as-design discipline forward into the OO mainstream, and Sandi Metz's POODR (2012; 2nd ed. 2018) is the most thorough single treatment of when not to reach for a pattern, and what the right names look like when you do.3
Martin Fowler's Patterns of Enterprise Application Architecture (2002) extended the catalogue upward to the architectural layer (Repository, Unit of Work, Data Mapper, Active Record) and made those names load-bearing in every web framework written since.8 The modern accessible reference is refactoring.guru: free, illustrated, the entry point most engineers under thirty-five reach for first. Refactoring Guru is what teams cite in code review now. The GoF book is what the citations point at.
The naming-rule half of PT1 is older still. Brian Kernighan and P. J. Plauger's The Elements of Programming Style (1974) puts it in five words: “say what you mean, simply.”9 Decades before Clean Code, the discipline of letting the identifier hold the design was in print. PT1 is that rule plus the catalogue: the name says what it is and the name has to match the canonical word the catalogue already gave us.
Quotes
Each design pattern systematically names, explains, and evaluates an important and recurring design in object-oriented systems.
Informal: Design pattern in prose; refer to by name, but must be implemented from scratch for each use
Pattern misapplication results in complicated and confusing code, but this result is not the fault of the pattern itself. A tool cannot be faulted for its use; the user must master the tool.
Instead of compensating for poor variable, method, class, or test names, rename them.
Evidence
16 external sources, ranked by author authority. The first five are the canon; expand to see the rest, including the qualifiers and the named opposers. Each links out to its primary source.
- 01The book that gave the industry the words. The 23 patterns are a vocabulary. The lasting contribution is the names (Strategy, Singleton, Visitor, Factory) that two engineers can use without describing the thing from first principles.
- 02Design PatternsSupportsThe free, illustrated, modern walkthrough of the GoF patterns plus Fowler's refactorings. The reference most engineers under thirty-five reach for first. Supports the naming-as-vocabulary rule with worked examples in ten languages.
- 03Extends the GoF vocabulary upward to the architectural layer. Repository, Unit of Work, Data Mapper, Active Record: every web framework written since uses these names. Confirms vocabulary is the lasting contribution.
- 04Smalltalk Best Practice PatternsSupportsPost-GoF treatment of naming-as-design. Treats names as primary. The word in the identifier holds the design intent. The closest predecessor to PT1's naming rule.
- 05The deepest single treatment of when not to reach for a pattern. Naming is part of the discipline, but Metz's rule is to name only when the pattern is real, never to manufacture one for the sake of vocabulary.
- 06“A Pattern Language”SupportsThe architectural-design forebear the GoF authors cite directly. A pattern names a recurring problem and a vocabulary for its solution. Without the name, the solution can't be reused across teams.
- 07The strongest steelman. In a language with first-class functions and dynamic dispatch, sixteen of the twenty-three GoF patterns become invisible or one-liners. The reply: the vocabulary outlives the class hierarchy.
- 08The cultural-not-technical critique. Treating every concept as a noun-class produces ceremonial code. Pattern-as-class-name is one of the bars. PT1's reply is to make the rule descriptive, not coercive.
- 09The lint hook that makes the naming rule enforceable in TypeScript. Suffixes, prefixes, casing: all configurable. The only foothold linters get inside the patterns layer.
- 10“N801” Invalid Class Name ruleSupportsRuff's Python equivalent of the naming-convention rule. Confirms the lint exception generalises across language ecosystems. Not a TypeScript peculiarity.
- 11PMD ClassNamingConventionsSupportsJava equivalent. ClassNamingConventions is one rule with a regex per kind of declaration: classPattern, abstractClassPattern, interfacePattern, enumPattern, annotationPattern, utilityClassPattern, testClassPattern. The Java ecosystem treats this as routine; PT1 says the same instinct should be universal.
- 12Vocabulary in identifiers, prose for what they can't carry. Henney's distinction supports PT1: name what the pattern is. If the name doesn't hold it, fix the name first.
- 13Game Programming PatternsSupportsGoF reframed for game developers, with sharper prose and concrete examples. Every chapter opens with the canonical pattern name. Demonstrates the vocabulary is portable across application domains.
- 14Wikipedia: Design Patterns (book)QualifiesIncludes the famous note that Erich Gamma said in 2009 he would remove Singleton from a revised GoF. The vocabulary persists. Specific patterns can age out (cross-link PT3).
- 15“When Polymorphism Fails”OpposesThe case that Visitor exists because OO can't double-dispatch: the vocabulary masks a type-system surrender. Naming the Visitor 'Visitor' makes the surrender visible (which is the right outcome).
- 16Effective Java, 3rd editionSupportsItem 1 “Consider static factory methods instead of constructors”: explicit on the convention names (from / of / valueOf / instance / getInstance / create / newInstance). The naming discipline at industrial scale.
Sixteen sources, three stances. The supporters are the canon: Gamma et al. (GoF), Refactoring Guru, Fowler's PoEAA and Beck's Smalltalk Best Practice Patterns. The qualifiers further down hold the “name the right thing” nuance: name a pattern only when it is real, never manufacture one for the sake of vocabulary. The opposers are the ones the reply has to address: when the pattern is just a function, naming it as a pattern is ceremony.
Examples
Before the class is a Factory, but ls -la cannot tell.
export class HedgehogMaker { make(name: string, prickleCount: number): Hedgehog { return new Hedgehog(name, prickleCount); } }
After the pattern name lives in the type and the file.
export interface Factory<T> { create(...args: readonly unknown[]): T; } export class HedgehogFactory implements Factory<Hedgehog> { create(name: string, prickleCount: number): Hedgehog { return new Hedgehog(name, prickleCount); } }
Before the class is a Factory, but ls -la cannot tell.
export class HedgehogMaker { make(name: string, prickleCount: number): Hedgehog { return new Hedgehog(name, prickleCount); } }
After the pattern name lives in the type and the file.
export interface Factory<T> { create(...args: readonly unknown[]): T; } export class HedgehogFactory implements Factory<Hedgehog> { create(name: string, prickleCount: number): Hedgehog { return new Hedgehog(name, prickleCount); } }
Before the class is a Factory, but ls cannot tell.
export class HedgehogMaker { make(name, prickleCount) { return new Hedgehog(name, prickleCount); } }
After pattern name lives in the file and class.
/** @typedef {{ create(...args: unknown[]): Hedgehog }} HedgehogFactoryShape */ export class HedgehogFactory { create(name, prickleCount) { return new Hedgehog(name, prickleCount); } }
Before the class is a Factory, but ls cannot tell.
class HedgehogMaker: def make(self, name: str, prickle_count: int) -> Hedgehog: return Hedgehog(name, prickle_count)
After the pattern name lives in the type and the file.
class Factory(Protocol[T]): def create(self, *args: object) -> T: ... class HedgehogFactory(Factory[Hedgehog]): def create(self, name: str, prickle_count: int) -> Hedgehog: return Hedgehog(name, prickle_count)
Before the class is a Factory, but ls cannot tell.
public class HedgehogMaker { public Hedgehog make(String name, int prickleCount) { return new Hedgehog(name, prickleCount); } }
After the pattern name lives in the type and the file.
public interface Factory<T> { T create(Object... args); } public class HedgehogFactory implements Factory<Hedgehog> { public Hedgehog create(String name, int prickleCount) { return new Hedgehog(name, prickleCount); } }
Before the class is a Factory, but ls cannot tell.
final class HedgehogMaker { public function make(string $name, int $prickleCount): Hedgehog { return new Hedgehog($name, $prickleCount); } }
After the pattern name lives in the type and the file.
interface Factory { public function create(): object; } final class HedgehogFactory implements Factory { public function create(string $name, int $prickleCount): Hedgehog { return new Hedgehog($name, $prickleCount); } }
AI rules
.cursor/rules/pt1-patterns-are-vocabulary.mdc--- alwaysApply: true --- ## Prickles PT1: Patterns Are Vocabulary If a class implements a known pattern, name the pattern in the identifier. A Factory is `*Factory`. A Repository is `*Repository`. An Adapter is `*Adapter`. An Observer is `*Observer`. An abstract base is `Abstract*` or marked `abstract` in the language. Read GoF, Refactoring Guru, or Fowler's PoEAA once so the names mean the same thing across team and code. Do not paraphrase the catalogue. Cite it. Refuse to introduce a pattern unless the pattern is unmistakable from the requirement. When the pattern is real, name it. When it isn't, don't manufacture one. If you discover the code already implements a pattern after the fact, rename it to the canonical word. A Repository called `OrderStore` is a missed signal. Rename it `OrderRepository`.
Repo layout, CI, and ESLint wiring for these paths live on /implementation, not repeated on every tenet.
Counter-argument
The strongest steelman is Peter Norvig's.4 In a language with first-class functions and dynamic dispatch, sixteen of the twenty-three GoF patterns become invisible or one-liners: Strategy is a function passed as an argument; Iterator is a generator; Command is a closure. Insisting on the GoF vocabulary in those cases is performing patterns rather than using them and the “call a Factory a Factory” rule risks pushing teams toward Java-shaped class hierarchies in languages that explicitly do not need them. Steve Yegge sharpens the same point: the kingdom of nouns is a cage, and pattern-as-class-name is one of its bars.5
Counter-argument retort
Norvig is right about dynamic-language patterns and the rule still stands. The vocabulary isn't the class hierarchy but the word itself. A higher-order function that produces an instance is still a Factory. Naming the file order-factory.ts when the export is a function called createOrder tells the reviewer this is the place new orders come from: the same signal a class would carry, without the ceremony Norvig objects to.4
Yegge's “kingdom of nouns” argument5 is the harder one and the reply is to treat the vocabulary as descriptive, not coercive. PT1 doesn't say “turn every function into a noun-class.” It says “if you've already got a Repository, call it one.” A team writing functional TypeScript that has zero classes still has Repositories: they're modules withfind / save / delete exports talking to a store. Naming the module order-repository.ts justifies itself the same way the class name would. The vocabulary is the constraint that survives the language change.
The genuine residue is the over-naming risk: calling a function a Strategy because two callers exist. The naming half of PT1 doesn't solve that. The other half does. PT1 says: when the pattern is real, name it. It also says: don't manufacture patterns from coincidence. Both halves are needed. Neither is sufficient on its own. The reviewer's question becomes “is this a Strategy, and if so why isn't it called one?”: one question, two rules behind it.
One lint rule reaches into this layer. ESLint's @typescript-eslint/naming-convention, Ruff's N801, PMD's ClassNamingConventions: the first and third can require a prefix or suffix by kind of class (abstract or exported in ESLint; abstract, utility or test in PMD), and N801 only checks that a class name is CapWords.6 That is the only foothold linters have inside the patterns layer. Everything else (pattern misuse, anti-pattern detection, “you should have used Strategy here”) is unreachable to static analysis. TA1 Linter as Law names the boundary and PT1 is the only place the tooling reaches across it.
Notes
- [1]Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). The lasting contribution is the names: Strategy, Singleton, Visitor, Factory. Without the words, the patterns would have been re-invented in every team rather than reused.
- [2]Refactoring Guru: Design Patterns reference (refactoring.guru/design-patterns). Each entry names the pattern, its intent, its structure, and crucially the conventional class-name suffix or prefix that flags an instance of the pattern in code review.
- [3]Sandi Metz: Practical Object-Oriented Design in Ruby (POODR), 2nd ed. (2018). The deepest single treatment of when not to reach for a pattern; Chapter 6 on inheritance is the canonical statement that a pattern misnamed is a pattern misused.
- [4]Peter Norvig: “Design Patterns in Dynamic Languages” (1996). Sixteen of the twenty-three GoF patterns become invisible or one-liners in a language with first-class functions and dynamic dispatch. The reply: the vocabulary outlives the class hierarchy.
- [5]Steve Yegge: “Execution in the Kingdom of Nouns” (2006). The cultural critique of treating every concept as a noun-class, where pattern-as-class-name is one of the bars. PT1's reply is to make the rule descriptive rather than coercive.
- [6]typescript-eslint maintainers: @typescript-eslint/naming-convention rule. The lint hook that makes the suffix / prefix rule enforceable. Ruff's N801 and PMD's ClassNamingConventions are the Python and Java equivalents: the same idea, three ecosystems.
- [7]Christopher Alexander: A Pattern Language: Towns, Buildings, Construction (Oxford UP, 1977). The architectural-design book the GoF authors cite directly. A pattern names a recurring problem and a vocabulary for its solution.
- [8]Martin Fowler: Patterns of Enterprise Application Architecture (Addison-Wesley, 2002). Repository, Unit of Work, Data Mapper, Active Record: extends the GoF vocabulary to the architectural layer. Every web framework written since uses these names.
- [9]Brian W. Kernighan & P. J. Plauger: The Elements of Programming Style (McGraw-Hill, 1974; 2nd ed. 1978). “Say what you mean, simply.” Half a century before Clean Code, the discipline of letting the identifier hold the design was in print.