Design Patterns

Each pattern as a response to an observed problem, with its trade-off and its simpler alternative — because a pattern applied without the problem is just indirection.

Patterns as Vocabulary

Their durable value is a shared name for a shape you already built. Treated as a construction kit instead of a naming scheme, they add structure nobody needed.

Q · What are design patterns actually for, given that most codebases would be worse if they contained more of them?
Strategy

Behaviour that varies by a recurring kind, held in a value instead of a conditional. Worth it when the variation is real and stable — and a map of functions usually gets you there first.

Q · A pricing conditional appears in four places. When is that a strategy, and when is it a function I should have passed in?
Factory

Encapsulates a construction decision that callers should not make. When there is no decision, a factory is a function that calls `new` and charges you a file for it.

Q · When does creating an object deserve its own abstraction, and when is `new Thing()` the right answer forever?
Adapter

Your interface on one side, someone else's on the other, and a translation in between. The most consistently useful pattern here, because it is an anti-corruption layer in miniature.

Q · A third-party client does not match how my code thinks. Do I bend my code to it, or put something in between?
Facade

A small interface over a subsystem whose full surface most callers do not need. Useful when the subsystem is genuinely complex and dangerous when the facade becomes the only way in.

Q · Six callers use four of my subsystem's twenty types to do the same three-step thing. Should there be one entry point?
Decorator

Add behaviour by wrapping rather than by editing. Excellent for logging, caching and retry; the cost is a stack trace nobody can read and behaviour that depends on wrapping order.

Q · I need logging, caching and retry around a client. Do I put them inside it, wrap it, or leave them at the call site?
Observer

The producer stops knowing its consumers. That is the point and the price: nothing in the code shows what happens when the event fires.

Q · Order confirmation needs to send an email, update inventory and notify analytics. Should the order module call those, or announce something and let them listen?
Command

An action turned into a value. Pointless if you only intend to call it — and genuinely load-bearing the moment you need to queue, retry, audit, schedule or undo it.

Q · When is it worth representing "do this" as data rather than just doing it?
State Pattern
▶ lab

Behaviour that varies by lifecycle state, held in a type per state. Often the right instinct — and an explicit state machine is usually the clearer way to satisfy it.

Q · My order class is full of `if (status === ...)`. Is a class per state the fix, or is the fix a transition table?
Template Method

A base class fixes the steps and subclasses fill in two of them. It works, and passing the two steps in as functions does the same job without a hierarchy.

Q · Four import jobs share the same seven steps and differ in two. Should the shared part be a base class?
Pattern Overuse
▶ lab

The anti-lesson. Abstractions with one implementation, event buses for local calls, factories of factories — structure added for problems nobody has, and it is not free.

Q · How do I tell a design that is prepared for change from one that has been decorated with structure?