Install any skill in seconds. Free to start, no credit card required.
Get Started Free →DDD-guided legacy refactoring patterns -- strangler fig, bubble context, ACL migration, 14 tactical/strategic/infrastructure patterns, and incremental monolith-to-microservices methodology
.claude/skills/nwave-ai-nw-legacy-refactoring-ddd/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 91% | 0% |
Refactoring legacy systems using Domain-Driven Design as the strategic compass. DDD tells you WHERE and WHY to refactor; traditional techniques (progressive-refactoring, mikado-method) tell you HOW.
Principle: "Start simple, grow big" -- incremental steps tested at each stage.
Ask three questions before any DDD refactoring:
| Cynefin Domain | Refactoring Approach | |---------------|---------------------| | Clear | Apply established patterns directly; standard refactoring catalogs | | Complicated | Analyze with experts, then apply patterns; multiple valid solutions | | Complex | Probe with safe-to-fail experiments; EventStorming to discover patterns | | Chaotic | Act first to stabilize, then refactor; emergency patches acceptable | | Confusion | Gather information before deciding; avoid premature refactoring |
Build new DDD-modeled functionality alongside legacy. Route requests to new code as features complete. Legacy gradually shrinks until fully replaced. Changes are incremental, monitored, low risk of unexpected breakage.
Mikado integration: use Mikado exploration to discover dependencies between legacy components before extracting. Each Mikado leaf becomes an atomic refactoring step.
Create a small bounded context (the "bubble") where DDD principles apply. The bubble communicates with legacy through an Anti-Corruption Layer. Progressively expand the bubble to encompass more legacy functionality.
Steps:
Integration patterns change as refactoring progresses. Map current relationships, identify mismatches, propose new patterns. Typical evolution: Conformist -> Customer-Supplier with ACL -> Partnership.
When a context grows too large or serves conflicting purposes:
Validation: bounded context splits are driven by business evolution, not technical convenience. Validate with domain experts.
When separation causes more friction than value:
These patterns apply tactical DDD concepts (aggregates, value objects, domain events, domain services, CQRS) to refactoring. For foundational definitions and design rules, load domain-driven-design from solution-architect/.
| Pattern | What It Fixes | Key Step | |---------|--------------|----------| | Replace primitives with VOs | Primitive obsession | Create self-validating type, replace in aggregate, update mapping | | Enrich anemic model | Logic in services, data in entities | Move business rules from service "if" statements into owning entity | | Introduce domain events | Direct coupling between aggregates | Replace method calls with immutable past-tense events + handlers | | Extract domain service | Cross-aggregate operations in application layer | Create stateless domain-typed service; guard against overuse | | Introduce CQRS | Read/write contention on same model | Separate read DTOs from write aggregates; CQRS != event sourcing |
Most challenging aspect of DDD refactoring. Use expand/contract pattern for safe migration.
When contexts need data owned by another context:
Prepare for microservice extraction. Mediator is a stepping stone, not a destination.
Only when module is stable, independently deployable, and business-justified.
Measure refactoring progress with automated fitness functions in CI:
| Metric | What It Measures | Tool Examples | |--------|-----------------|---------------| | Afferent coupling | Incoming dependencies to module | NDepend, SonarQube, jdepend | | Efferent coupling | Outgoing dependencies from module | Same | | Dependency direction | Dependencies flow correctly (inward) | ArchUnit, NetArchTest | | Test coverage | Safety net for refactoring | Coverage tools | | Cohesion | Relatedness of components within module | LCOM metrics |
Define fitness function thresholds as acceptance criteria for refactoring stories.
| Test Type | When | Purpose | |-----------|------|---------| | Characterization tests | Before touching legacy code | Document current behavior as safety net | | Contract tests | When splitting contexts | Verify interservice communication | | Eventual consistency tests | After introducing events | Simulate network failures, verify convergence | | Schema integrity tests | During database refactoring | Verify constraints and data integrity |
Characterization tests (Feathers): run legacy code, observe output, write tests that assert current behavior -- even if behavior seems wrong. These tests protect against unintended changes during refactoring.
Other measured skills in the registry, with their headline benchmark lift.