SKILL.md
Strategy Pattern (TypeScript)
Intent
Encapsulate a family of algorithms behind a common interface so the client can select and swap behavior without changing the context.
When to use
- Route planning variants (driving, walking, transit, cycling).
- Pricing, tax, or discount policies that vary by customer or region.
- Export formats (CSV, JSON, XML) with shared context API.
- Search ranking/scoring options that change by feature flag.
- Authorization policies that are interchangeable by tenant.
- Retry/backoff policies that are algorithmic and configurable.
- Parsing strategies for different input formats.
- Feature-flagged behavior that should not introduce switch ladders.
When NOT to use
- Only a few stable variants exist and conditionals are clear.
- The behavior changes based on lifecycle state transitions (State).
- You need to queue/log/undo requests (Command).
- You need a fixed algorithm skeleton with overridable steps (Template Method).
- Differences are data-only and can be captured as configuration.
- The context would still branch to select variants everywhere.
- It would introduce over-abstraction and add little value.
- The strategies require heavy shared state that belongs in the context.
Mental model
Context owns the workflow and delegates the variable part to a strategy; the client selects the strategy; strategies do not manage the context lifecycle.
Recommended TS shapes
- OO:
interface RouteStrategy { buildRoute(input): Route }. - Functional:
type StrategyFn = (input) => output. - Registry:
Record<StrategyKey, Strategy>with selection and validation.
Example 1: Navigation routing strategies
Select driving/walking/transit at runtime without context conditionals.
Example 2: Pricing/discount policy strategies
Isolate dependencies and validate inputs before applying a strategy.
Example 3: Export format strategies
Select by key; unknown key yields a typed error.
Testing strategy (pragmatic)
- Per-strategy unit tests with shared fixtures.
- Contract tests to ensure each strategy satisfies the same interface.
- Selection tests (valid/invalid keys).
- Edge cases for parameter validation without extra libraries.
Common pitfalls
- Too many tiny strategies with unclear responsibilities.
- Selection logic leaking into the context.
- Inconsistent interfaces across strategies.
- Strategies mutating global state or shared singletons.
- Hidden shared dependencies not passed via constructor.
- Overusing inheritance where composition is simpler.
- Premature optimization with strategy objects on hot paths.
- Missing default strategy or unknown-key handling.
- Mixing data configuration and algorithm selection.
- Allowing strategies to mutate context invariants.
Checklist for refactors
- Identify the conditional hotspot in the context.
- Extract a clean strategy interface.
- Move each branch into its own strategy.
- Provide a selection mechanism (DI or registry).
- Remove context branching once selection is externalized.
- Validate selection keys and inputs.
- Add per-strategy tests and shared fixtures.
- Document strategy keys, defaults, and selection rules.
Output expectations
When invoked, produce: interface, concrete strategies, selection mechanism (DI/registry), removal of conditionals, and runnable TS examples tailored to the user input.