When NOT to Use a Pattern
When NOT to use a pattern is the most under-taught topic in design patterns.
Introduction
When NOT to use a pattern is the most under-taught topic in design patterns. Seniors spend careers removing premature abstractions. This lesson catalogs seven walk-away situations: single variant, hypothetical roadmap, team size, performance hot paths, prototype code, simpler primitive available, and recency bias from last week's book.
The story
A staff engineer kept a "Patterns I Removed" list — 28 entries by tenure end: interfaces with one implementation, factories returning fixed classes, observers with one subscriber. Each removal made the codebase smaller, faster, and easier to onboard.
The business problem
Reflexive pattern application costs more than it saves:
- One-impl interfaces: every reader navigates seam with no benefit.
- Hypothetical variants: "what if SMS?" abstractions never used.
- Review theater: patterns please reviewers, not users.
- Onboarding tax: new hires learn abstraction zoo before domain.
The problem teams faced
Skip the pattern when:
- Only one implementation exists and no credible second variant on roadmap.
- Team is 2-3 engineers — direct code beats ceremony.
- Hot path where indirection costs measurable latency.
- Throwaway prototype or spike — YAGNI applies hardest here.
- Language primitive suffices — function over Strategy for one algorithm.
- You applied it because you read about it last week.
Understanding the topic
Intent: Confidently defend "no pattern" with named criteria.
- Rule of Three — wait for third duplication before abstracting.
- YAGNI — you aren't gonna need that Factory yet.
- Simplest thing — function, class, module — until force appears.
- Kill switch — document when you'll add pattern later.
Internal architecture
Decision gate before introducing pattern:
function shouldApplyPattern(context: Context): boolean {if (context.implementations === 1 && !context.credibleSecondVariant) return falseif (context.isPrototype) return falseif (context.teamSize <= 3 && !context.sharedLibrary) return falseif (context.simplerPrimitiveExists) return falsereturn context.duplicationCount >= 3 || context.variationIsProven}
Visual explanation
Three diagrams cover seven skip situations, Rule of Three, and removal list:
Informative example
Before / after — premature Factory to direct construction:
// ❌ Factory for one product typeclass NotificationFactory {create(): EmailNotifier { return new EmailNotifier() }}// ✅ Direct until second channel provenconst notifier = new EmailNotifier()// When SMS ships for real:interface Notifier { send(msg: Message): void }// Strategy with Email + Sms implementations
Execution workflow
Name the force
What problem does pattern solve?
Real-world use
Staff engineer deletion sprints; YAGNI from XP; Rule of Three from Fowler; "Patterns I Removed" as team learning artifact.
Production case study
Staff engineer 28 removals:
- Symptoms: 1-impl interfaces, fixed factories, lonely observers.
- Action: deletion PRs with before/after line counts.
- Outcome: smaller codebase, faster onboarding, fewer mocks.
Trade-offs
- Pro: less ceremony; faster reads; fewer mocks in tests.
- Con: may refactor later when variant arrives — that's OK.
- Con: junior reviewers may flag "missing pattern" — educate.
Decision framework
- Proven variation → pattern. Hypothetical → wait.
- Document "will add Strategy when second ship mode ships."
- Quarterly review: delete abstractions that never got second impl.
Best practices
- ADR alternatives section: "considered Factory, rejected — one product."
- PR template: "what force does this abstraction resolve?"
- Celebrate deletion PRs same as feature PRs.
Anti-patterns to avoid
- Pattern because code review expects "professional" structure.
- Interface for testability when function injection suffices.
- Abstract Factory with one concrete family forever.
Common mistakes
- Deferral becomes permanent — set review date in ADR.
- Confusing "no pattern" with "no structure."
Debugging tips
- grep for interfaces with single implementor — deletion candidates.
Optimization strategies
- Static analysis: count implementations per interface — flag singletons.
Common misconceptions
- Senior ≠ most patterns — senior = fewest necessary abstractions.
- DI container ≠ need Factory everywhere — container resolves concretions too.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1IntermediateQuestionWhen would you NOT use Strategy?+
Answer
Follow-up
2AdvancedQuestionHow defend 'no pattern' in review?+
Answer
Follow-up
3IntermediateQuestionPattern on 2-person startup?+
Answer
Follow-up
Summary
You can name seven skip situations and defend "no pattern" with evidence. Tell the 28-removals story — if you can do that, you own When NOT to Use.