← All posts

Design Patterns (GoF): vocabulary, not a goal

GoF digest: patterns as named solutions, Strategy and Observer today, pattern fever trap, AI cargo-cult — with cases and actions for today.

Design Patterns (GoF): vocabulary, not a goal
Contents

Two developers argue in code review. One says: "we need a Decorator here." The other: "it's just an if." A month later — three wrapper layers nobody can trace, and a bug in call order. Sound familiar?

Design Patterns (GoF, 1994) is not a checklist to insert a pattern into every module. It is a vocabulary for recurring design problems: name a solution, discuss it in review, avoid reinventing alone. Below — how the book reads in 2026, where it becomes cargo-cult, and how AI worsens "pattern soup." This digest does not replace the book.

The book's thesis

A design pattern is a named, proven solution to a recurring problem in object-oriented systems. GoF gives language: Strategy, Observer, Factory Method — not buzzwords, but references to structure, trade-offs, and consequences.

Examples in C++ and Smalltalk aged syntactically; problems remain: isolate change, connect objects without spaghetti, create object families. The classic reader mistake is memorizing 23 patterns and hunting slots for each. Better — recognize the situation and recall the move, like a chess player recognizes a line.

Key ideas

Pattern as team vocabulary, not KPI

What the author says. A pattern captures problem, context, solution, consequences. Saying "Facade" or "Adapter" saves ten minutes on the whiteboard. Goal is shared language, not a "we use patterns" badge.

Enterprise. Bank API changes every quarter. Instead of "wrapper over wrapper," review says: "Adapter with a narrow domain interface." New hire opens the catalog, sees structure, does not rewrite from scratch.

AI today. Models generate AbstractFactory and Visitor where a function suffices. Diff looks "architectural," review misses it. Ask: "describe the problem without a pattern; then suggest one GoF name if truly needed."

Where it fails. Small CRUD — plain names beat pattern jargon.

Do today. On next review ask: "what problem are we solving?" before naming a pattern.

My take. GoF saves cross-team talk and legacy onboarding. When the pattern becomes the goal — the book hurts.

One takeaway: problem first, catalog name second.

Program to an interface, not an implementation

What the author says. Depending on abstractions lowers coupling: swap implementations, test with fakes, evolve subsystems separately.

Enterprise. Notification service depends on Notifier, not a concrete SMS gateway. New channel — new implementation, domain unchanged.

AI today. "Interface per class" zoo — one-method interfaces everywhere. Human filter: two implementations or real swap ahead?

Where it fails. YAGNI before second implementation. In TS, unions often play the interface role — same idea, different shape.

Do today. Find one concrete-class dependency in your task — need swap in tests or next release?

My take. The most alive GoF line in 2026. The rest are special cases of not nailing code to one implementation.

One takeaway: interface where a second implementation is coming.

Favor composition over inheritance

What the author says. Inheritance binds subclasses tightly; composition (contain and delegate) flexes. Decorator, Strategy, Bridge — about this.

Enterprise. Extending a report class per format (PDF, Excel, API) explodes hierarchy. Strategy for renderer + composed report data — add format without touching base.

AI today. Deep inheritance trees "look OOP." Catch when extends should become field + delegation.

Where it fails. Some frameworks mandate inheritance; domain code usually prefers composition.

Do today. One extends in your task — replaceable with composition?

My take. Links to Fowler's Refactoring — Replace Inheritance with Delegation.

One takeaway: inheritance for stable is-a; behavior via composition.

Creational: flexible creation, not Singleton by default

Factory Method, Abstract Factory, Builder, Prototype — who creates how when new is not enough. Singleton — creational with caveats.

Enterprise. Builder for documents with many optional fields beats 14-arg constructors. Factory picks PaymentGateway from config. Singleton DB "the one connection" — test and scale pain.

AI today. Singleton "for cache" = global state. Review: one instance per process or lazy habit?

Do today. See Singleton — ask how tests avoid global state.

My take. Builder and Factory stay daily; new-code Singleton is a red flag unless OS-level resource.

One takeaway: creational patterns are about creation variants, not pretty factories.

Behavioral: Strategy and Observer for change

Strategy — interchangeable algorithms. Observer — notify without tight coupling. Command, State, Iterator — other answers to how objects collaborate.

Enterprise. Tax rules by country — Strategy, not 200-line switch. UI on model change — Observer (or events, reactive streams).

AI today. Generates switch; Strategy refactor is a good post-test agent task. Microservices often use brokers — subscribers still don't know each other.

Do today. One big type/status switch — Strategy candidate?

My take. Strategy and Observer survive in legacy most often.

One takeaway: behavioral patterns buy behavior change flexibility.

Structural: Adapter and Facade at boundaries

Adapter — foreign interface to yours. Facade — simple entry to complex subsystem. Decorator — add duties without subclasses. Proxy — control access.

Enterprise. SOAP outside, REST inside — Adapter for domain. Facade over five billing services — one "issue invoice" for frontend. Good Facade narrows surface, not pass-through every method.

AI today. Useless Facades that only delegate everything.

Do today. At external API boundary sketch: our interface vs theirs — need Adapter?

My take. Facade and Adapter are daily integration horses.

One takeaway: structural patterns live at boundaries and layers.

In practice

On review: problem before pattern name? Simpler solution without new layer? Hooks/middleware/plugins are often the same ideas — find dependency shape, not class named Observer.

Idea Junior Middle Senior
Pattern as vocabulary ★★★★ ★★★★★ ★★★★★
Interface vs implementation ★★★★★ ★★★★★ ★★★★
Composition vs inheritance ★★★★ ★★★★★ ★★★★★
Creational ★★★★ ★★★★★ ★★★★
Behavioral ★★★★ ★★★★★ ★★★★★
Structural ★★★★ ★★★★★ ★★★★★

Limits and critique

GoF examples age, problems don't. Pattern-omania worse than no catalog. Much is built into frameworks. FP questions some OO forms — "isolate change" remains.

Compare. GoF — named shapes. Clean Code — local readability. Refactoring — change form safely. DDD — which model; GoF — how objects connect.

Read GoF as reference and language, not 23 Jira checkboxes.

Who should read

Worth it for non-trivial modules, integrations, changing rules, legacy with Factory/Observer. Selective if framework gives everything — know 5–6 patterns from articles. Caution if team counts patterns as architecture metric.

What to try today

  1. Name one problem in current module — one GoF pattern or simple refactor?
  2. One type switch — Strategy only if variants grow or tests need swap.
  3. On AI diff — no new class hierarchies without "which problem."
  4. Read one original chapter (Strategy or Adapter) against your code.