design-patterns

Use when designing software architecture, refactoring code structure, solving recurring design problems, or when code exhibits symptoms like tight coupling, rigid hierarchies, scattered responsibilities, or difficult-to-test components. Also use when choosing between architectural approaches or reviewing code for structural improvements.

$ Installer

git clone https://github.com/ratacat/claude-skills /tmp/claude-skills && cp -r /tmp/claude-skills/skills/design-patterns ~/.claude/skills/claude-skills

// tip: Run this command in your terminal to install the skill


name: design-patterns description: Use when designing software architecture, refactoring code structure, solving recurring design problems, or when code exhibits symptoms like tight coupling, rigid hierarchies, scattered responsibilities, or difficult-to-test components. Also use when choosing between architectural approaches or reviewing code for structural improvements.

Design Patterns

Overview

Design patterns are proven solutions to recurring software design problems. They provide a shared vocabulary for discussing design and capture collective wisdom refined through decades of real-world use.

Core Philosophy: Patterns are templates you adapt to your context, not blueprints to copy. Use the right pattern when it genuinely simplifies your design—not to impress or over-engineer.

Foundational Principles

These principles underpin all good design:

PrincipleMeaningViolation Symptom
Encapsulate What VariesIsolate changing parts from stable partsChanges ripple through codebase
Program to InterfacesDepend on abstractions, not concretionsCan't swap implementations
Composition Over InheritanceBuild behavior by composing objectsDeep rigid class hierarchies
Loose CouplingMinimize interdependency between objectsCan't change one thing without breaking another
Open-ClosedOpen for extension, closed for modificationMust edit existing code for new features
Single ResponsibilityOne reason to change per classClasses doing too many things
Dependency InversionHigh-level modules don't depend on low-levelBusiness logic coupled to infrastructure

Pattern Selection Guide

By Problem Type

CREATING OBJECTS
├── Complex/conditional creation ──────────→ Factory Method
├── Families of related objects ───────────→ Abstract Factory
├── Step-by-step construction ─────────────→ Builder
├── Clone existing objects ────────────────→ Prototype
└── Single instance needed ────────────────→ Singleton (use sparingly!)

STRUCTURING/COMPOSING OBJECTS
├── Incompatible interface ────────────────→ Adapter
├── Simplify complex subsystem ────────────→ Facade
├── Tree/hierarchy structure ──────────────→ Composite
├── Add behavior dynamically ──────────────→ Decorator
└── Control access to object ──────────────→ Proxy

MANAGING COMMUNICATION/BEHAVIOR
├── One-to-many notification ──────────────→ Observer
├── Encapsulate requests as objects ───────→ Command
├── Behavior varies by internal state ─────→ State
├── Swap algorithms at runtime ────────────→ Strategy
├── Algorithm skeleton with hooks ─────────→ Template Method
├── Reduce N-to-N communication ───────────→ Mediator
└── Sequential handlers ───────────────────→ Chain of Responsibility

MANAGING DATA ACCESS
├── Abstract data source ──────────────────→ Repository
├── Track changes for atomic commit ───────→ Unit of Work
├── Ensure object identity ────────────────→ Identity Map
├── Defer expensive loading ───────────────→ Lazy Load
├── Map objects to database ───────────────→ Data Mapper
└── Shape data for transfer ───────────────→ DTO

By Symptom

SymptomConsider
Giant switch/if-else on typeStrategy, State, or polymorphism
Duplicate code across classesTemplate Method, Strategy
Need to notify many objects of changesObserver
Complex object creation logicFactory, Builder
Adding features bloats classDecorator
Third-party API doesn't fit your codeAdapter
Too many dependencies between componentsMediator, Facade
Can't test without database/networkRepository, Dependency Injection
Need undo/redoCommand
Object behavior depends on stateState
Request needs processing by multiple handlersChain of Responsibility

Domain Logic: Transaction Script vs Domain Model

FactorTransaction ScriptDomain Model
Logic complexitySimple (< 500 lines)Complex, many rules
Business rulesFew, straightforwardMany, interacting
OperationsCRUD-heavyRich behavior
Team/timelineSmall team, quick deliveryLong-term maintenance
TestingIntegration testsUnit tests on domain

Rule of thumb: Start with Transaction Script. Refactor to Domain Model when procedural code becomes hard to maintain.

Quick Reference

Tier 1: Essential Patterns (Master First)

PatternOne-LineWhen to UseReference
StrategyEncapsulate interchangeable algorithmsMultiple ways to do something, swap at runtimestrategy.md
ObserverNotify dependents of state changesEvent systems, reactive updatesobserver.md
FactoryEncapsulate object creationComplex/conditional instantiationfactory.md
DecoratorAdd behavior dynamicallyExtend without inheritancedecorator.md
CommandEncapsulate requests as objectsUndo/redo, queuing, loggingcommand.md

Tier 2: Structural Patterns

PatternOne-LineWhen to UseReference
AdapterConvert interfacesIntegrate incompatible codeadapter.md
FacadeSimplify complex subsystemsHide complexity behind simple APIfacade.md
CompositeUniform tree structuresPart-whole hierarchiescomposite.md
ProxyControl access to objectsLazy load, access control, cachingproxy.md

Tier 3: Enterprise/Architectural Patterns

PatternOne-LineWhen to UseReference
RepositoryCollection-like data accessDecouple domain from data layerrepository.md
Unit of WorkCoordinate atomic changesTransaction managementunit-of-work.md
Service LayerOrchestrate business operationsDefine application boundaryservice-layer.md
DTOShape data for transferAPI contracts, prevent over-exposuredto.md

Additional Important Patterns

PatternOne-LineWhen to UseReference
BuilderStep-by-step object constructionComplex objects, fluent APIsbuilder.md
StateBehavior changes with stateState machines, workflowstate.md
Template MethodAlgorithm skeleton with hooksFramework extension pointstemplate-method.md
Chain of ResponsibilityPass request along handlersMiddleware, pipelineschain-of-responsibility.md
MediatorCentralize complex communicationReduce component couplingmediator.md
Lazy LoadDefer expensive loadingPerformance, large object graphslazy-load.md
Identity MapEnsure object identityORM, prevent duplicatesidentity-map.md

Common Mistakes

MistakeSymptomFix
Pattern OveruseSimple operations require navigating many classesOnly use when solving real problem
Wrong PatternCode feels forced, awkwardRe-examine actual problem
Inheritance AbuseDeep hierarchies, fragile base classFavor composition (Strategy, Decorator)
Singleton AbuseGlobal state, hidden dependencies, hard to testUse dependency injection instead
Premature AbstractionInterfaces with single implementationWait for real need to vary

Anti-Patterns to Recognize

  • God Object: One class does everything → Split using SRP
  • Anemic Domain Model: Objects are just data bags → Move behavior to objects
  • Golden Hammer: Same pattern everywhere → Match pattern to problem
  • Lava Flow: Dead code nobody removes → Delete it, VCS has your back

Modern Variations

Modern PatternBased OnDescription
Dependency InjectionStrategy + FactoryContainer creates and injects dependencies
MiddlewareDecorator + Chain of ResponsibilityRequest/response pipeline
Event SourcingCommandStore state changes as events
CQRSCommand/Query separationSeparate read/write models
Hooks (React/Vue)Observer + StrategyFunctional lifecycle subscriptions

Implementation Checklist

Before implementing a pattern:

  • Pattern solves a real problem in this codebase
  • Considered simpler alternatives
  • Trade-offs acceptable for this context
  • Team understands the pattern
  • Won't over-engineer the solution