- Add principle 27: 'Language-Agnostic Auto-Trigger' to engineering-principles - Remove hardcoded English-only keyword lists from all 26 skill descriptions - Replace with concept-based detection: triggers from code context, project files, and file types regardless of spoken language - Update detect-project.sh hook output with language-agnostic message
5.5 KiB
5.5 KiB
name, description
| name | description |
|---|---|
| design-patterns | Guidance on Gang of Four design patterns and modern alternatives — when to use each pattern, how to implement it correctly, and when to avoid it. Use when designing class structures, solving recurring design problems, refactoring switch/if-else chains. Detects from code context and project files — not dependent on specific language keywords." |
Design Patterns
Patterns are solutions to recurring design problems. Use the right pattern for the right axis of change.
When to Use Patterns
- More types, fewer operations → OO patterns (polymorphism)
- More operations, fewer types → functional patterns (pattern matching, functions)
- Expected to change together? Keep them together in one abstraction.
- Expected to change independently? Separate them with an interface.
Creational Patterns
| Pattern | When | Why |
|---|---|---|
| Factory Method | A class can't know the type of objects it must create | Push creation decision to subclasses |
| Abstract Factory | Need families of related objects | Enforce compatibility across a product line |
| Builder | Object construction has many optional parts | Replace telescoping constructors |
| Singleton | Exactly one instance is needed | Avoid if possible — use dependency injection instead |
| Prototype | Creating objects is expensive; cloning is cheaper | Copy-on-write, configurable app |
Modern alternative: For factories, prefer passing a function/constructor directly ((config) => new Connection(config)) over a factory class.
Structural Patterns
| Pattern | When | Why |
|---|---|---|
| Adapter | Interface mismatch between expected and actual | Wrap, don't modify |
| Bridge | Abstraction and implementation vary independently | Decouple interface from implementation |
| Composite | Treat individual objects and compositions uniformly | Menu trees, file systems, UI trees |
| Decorator | Add responsibilities without subclassing | Middleware, streams, logging wrappers |
| Facade | Simplify a complex subsystem | Single entry point to complex system |
| Flyweight | Many fine-grained objects are too expensive | Share intrinsic state across instances |
| Proxy | Control access to another object | Lazy loading, caching, access control, logging |
Modern alternative: Middleware chains (e.g., Hono/Express middleware) are a functional take on Decorator. Proxy is often handled by AOP or proxy libraries.
Behavioral Patterns
| Pattern | When | Why |
|---|---|---|
| Strategy | Multiple algorithms for the same task | Pass behavior as a parameter |
| Observer | One-to-many dependency where state changes need notification | Event emitters, pub/sub |
| Command | Parameterize operations, queue, undo, log | Transaction logging, job queues |
| Template Method | Skeleton of algorithm varies in steps | Subclasses override specific steps |
| Iterator | Access elements sequentially without exposing structure | Built into every modern language |
| State | Object behavior changes when its state changes | State machines |
| Mediator | Reduce coupling between communicating objects | Chat rooms, UI coordination |
| Chain of Responsibility | Pass request along handler chain until one handles it | Middleware, validation pipelines |
| Visitor | New operation on a stable object structure | AST processing, serialization |
| Memento | Capture and restore internal state | Undo/redo, snapshots |
| Interpreter | Grammar interpretation | DSLs, parsers |
Modern alternative: Strategy → pass a lambda/closure. Observer → use reactive streams or event emitters. Command → functions are commands.
Pattern Selection Guide
Ask these questions:
- What is changing? Encapsulate what varies.
- What's the axis of change? More types (OO) or more operations (functional)?
- Is there a simpler alternative? A function parameter is often enough.
- Does the pattern add clarity or complexity? Patterns justify themselves only if they reduce overall complexity.
Modern Patterns (Post-GoF)
- Dependency Injection — pass dependencies in, don't create them internally
- Repository — abstraction over data access (not in GoF, but ubiquitous)
- CQRS — separate read and write models
- Event Sourcing — store events, derive state
- Saga — orchestrate distributed transactions
- Circuit Breaker — fail fast when downstream fails
Deeper Reference
When the task calls for it, load:
- references/catalog.md — Full GoF pattern catalog with code examples, real-world usage, modern alternatives, and "when to NOT use" guidance for each pattern.
Ask When Ambiguous
When multiple patterns could apply, present a brief comparison and ask which direction fits:
- "This could use Strategy (if algorithms vary) or polymorphism on a factory (if types vary). Which axis of change do you expect to grow?"
- If you're unsure what pattern fits, say so. Don't force a pattern where a simple function suffices.
- If the problem is too vague to pattern-match, ask clarifying questions first. A pattern chosen on partial input is technical debt.
Anti-patterns
- ❌ Pattern for pattern's sake — a simple function is better than a Strategy class with one implementation
- ❌ God Singleton — global state disguised as a pattern
- ❌ AbstractFactoryFactory — over-abstracting what should be a simple
new - ❌ The Blob — one class/function that does everything