Skip to content

Specification-Driven Planning

“Just start coding” works for small features. It does not work for modernization. Migration decisions are hard to reverse — extract the wrong bounded context first and you create a tangle of cross-domain dependencies. Choose the wrong data model and every subsequent module inherits the mistake. Skip the rollback plan and a failed migration becomes an incident.

Specifications prevent these problems by forcing clarity before code.

Alignment

Multiple teams need to agree on shared boundaries, API contracts, and migration sequence. A spec is the shared reference that prevents “I thought you were handling that” conversations.

Risk Reduction

Writing down what could go wrong (and the mitigation plan) before building is cheaper than discovering it in production. A spec’s risk section is a forcing function for this thinking.

Decision Record

Six months from now, someone will ask “why did we migrate payments before inventory?” The spec answers that question. Without it, the rationale is lost when the engineers who made the decision move on.

Scope Control

Modernization projects are magnets for scope creep. A spec with explicit “Won’t Have” boundaries gives teams a reference point when someone suggests adding “just one more thing.”

A modernization specification is not a single document — it is a small set of files, each serving a distinct purpose.

specs/
├── INDEX.md # Catalog of all specs
├── payment-extraction/
│ ├── spec.md # What and why
│ ├── plan.md # How and when
│ └── tasks.md # Actionable work items
├── inventory-migration/
│ ├── spec.md
│ ├── plan.md
│ └── tasks.md

This structure separates concerns:

  • spec.md captures intent, requirements, and design decisions
  • plan.md captures sequencing, phasing, and dependencies
  • tasks.md captures concrete work items derived from the plan

Changes to the plan do not require rewriting the spec. New tasks can be added without modifying the plan. Each file evolves at its own pace.

Every spec starts with 3-5 governing principles that guide all decisions. These are the tiebreakers when the team disagrees.

## Constitution
1. **Behavior preservation over modernization speed.**
Every migrated component must pass parity tests before cutover.
2. **Independent deployability.**
Each extracted service must be deployable without coordinating
with other services.
3. **Rollback within 15 minutes.**
Every migration step must be reversible without data loss
within 15 minutes.
4. **No big bang.**
Legacy and modern systems run in parallel until parity is proven.
Cutover happens per-module, not all at once.

The constitution is the most important section. When a developer asks “should I optimize this query or keep it identical to legacy?”, the constitution answers: behavior preservation comes first.

The plan translates the spec into sequenced work.

Break migration into phases that follow dependency order:

## Phases
### Phase 1: Foundation (Week 1-2)
- Define payment service API contract
- Set up service skeleton with build/test/deploy pipeline
- Create database migration scripts (forward + rollback)
- Write parity test fixtures from legacy system output
### Phase 2: Core Logic (Week 3-4)
- Extract payment processing business logic
- Extract refund workflow
- Wire to existing database (shared, not yet migrated)
- Run parity tests: target 100% pass rate
### Phase 3: Integration (Week 5-6)
- Connect order service to new payment service
- Deploy behind feature flag (1% traffic)
- Monitor error rates, latency, reconciliation accuracy
- Gradual rollout: 1% → 10% → 50% → 100%
### Phase 4: Cleanup (Week 7)
- Remove legacy payment code from monolith
- Remove feature flag
- Archive legacy reconciliation scripts

Record architecture decisions with rationale. This prevents relitigating settled decisions.

## Decision Log
| Date | Decision | Rationale | Alternatives Considered |
|------|----------|-----------|------------------------|
| 2026-01-15 | Shared database during migration | Avoids data sync complexity; extract database after service extraction | Separate database from day 1 (too risky) |
| 2026-01-18 | Feature flag per-endpoint, not per-service | Allows granular rollback; one failed endpoint doesn't roll back all | Service-level flag (too coarse) |
| 2026-01-22 | Keep Stripe API version until Phase 4 | Mixing extraction with API upgrade doubles risk surface | Upgrade during extraction (rejected: too many variables) |

Every spec must define measurable outcomes. Without them, “done” is subjective.

## Success Criteria
| Criterion | Measurement | Target |
|-----------|-------------|--------|
| Parity | All 47 legacy payment scenarios pass | 100% |
| Latency | P99 payment processing time | < 500ms (current: 450ms) |
| Availability | Payment service uptime | 99.95% over 30 days |
| Rollback | Time to revert to legacy path | < 15 minutes |
| Test coverage | New payment service code | > 90% |

TODO Lists Masquerading as Specs

A list of tasks without rationale, principles, or scope boundaries is not a specification. It tells the team what to do but not why or where to stop.

Missing Success Criteria

Without measurable outcomes, the project is never “done.” Teams keep adding work because there is no definition of complete.

No Won't Have Section

Scope creep is the leading cause of modernization project failure. Explicit boundaries prevent “while we are at it” expansions that delay delivery by months.

No Rollback Plan

Every migration step should be reversible. A spec that does not address “what if this fails?” is incomplete.

Prose specifications work for human teams. But modernization projects increasingly involve AI coding agents that benefit from structured, machine-readable specifications.

This is the core insight behind ModernizeSpec: specifications should be structured data that both humans and agents can consume.

FormatAudienceStrengths
Markdown specs (spec.md, plan.md)Human teamsReadable, flexible, supports nuance
JSON specs (domains.json, extraction-plan.json)AI agents + toolingParseable, validatable, queryable
Both togetherFull team (humans + agents)Best of both worlds

The markdown spec captures intent, rationale, and nuance. The JSON spec captures structure, sequencing, and measurable data. They complement each other — the markdown explains why, the JSON describes what in a format that tools and agents can process directly.

See the Specification Overview for the full ModernizeSpec file format.

If you have never written a modernization spec before, start with three things:

  1. Constitution — Write 3-5 principles. This takes 30 minutes and saves weeks of arguments.
  2. Scope boundaries — Write the Won’t Have section. This is the hardest part and the most valuable.
  3. Success criteria — Define 3-5 measurable outcomes. This tells you when to stop.

Everything else (phases, decision log, risk matrix) can be added as the project progresses. But these three establish the foundation that keeps modernization on track.