Design patterns
Patterns are named solutions to recurring design problems. They are vocabulary first and structure second — the value is that "this is a Strategy" tells a reader more than 40 lines of code do.
The gate: do you need one at all?
Apply before recommending any pattern. A pattern that fails the gate costs indirection and buys nothing.
- Two real cases now. A pattern that generalises over one implementation is speculation. One payment provider does not need an Abstract Factory.
- Name the pressure. Which change is hard today? If you cannot point at a concrete edit that hurts, there is no problem to solve.
- Try the cheap version first. A function, a dict/map lookup, a parameter, or a plain
ifbeats a class hierarchy until it visibly stops scaling. - Language features come first. First-class functions replace Strategy and Command. Generators replace Iterator. Decorators/higher-order functions replace the Decorator class. Modules replace Singleton. Reach for the classical structure only when the language idiom runs out.
If the gate fails, say so and propose the simpler design. Recommending a pattern is not the win condition.
Choosing
Match the pressure, not the vocabulary:
| Pressure | Look at |
|---|---|
| Creating an object needs many optional args | Builder |
| Which class to instantiate depends on input | Factory Method, Abstract Factory |
| A family of interchangeable algorithms | Strategy |
| Behaviour changes as an object's state changes | State |
| Many objects must react to one change | Observer |
| An action must be queued, logged, or undone | Command |
| A third-party interface doesn't match yours | Adapter |
| Add responsibilities per instance, not per class | Decorator |
| A messy subsystem needs one entry point | Facade |
| Uniform treatment of leaves and containers | Composite |
| Control access, defer cost, or add caching | Proxy |
| An algorithm's skeleton is fixed, steps vary | Template Method |
| A new operation over a stable type hierarchy | Visitor |
| Several handlers may process a request | Chain of Responsibility |
Full catalog with intent, fit, and trade-offs: references/PATTERNS.md
Applying
- State the pressure and the pattern in one sentence: "Payment methods vary per order, so
PaymentStrategy." - Name types after the pattern (
RetryPolicy,OrderObserver) — this is most of the benefit. - Introduce it by refactoring existing code, not by building the structure first and filling it in.
- Keep the seam narrow: one interface, obvious implementations.
- Write a test per implementation. If a pattern makes testing harder, it is the wrong pattern.
Reviewing existing code
Name what is already there ("this is a hand-rolled Observer") before proposing change — often the fix is to make an accidental pattern explicit, not to add a new one.
Over-engineering smells, and the four patterns most often misapplied: references/ANTIPATTERNS.md