Spec-Driven Development
On this page 16
Part VII — Engineering practices · Interview reference
Spec-driven development treats an explicit, versioned specification as the source of truth for behavior — before (or tightly alongside) implementation. For seniors, this is about reducing ambiguity, aligning contracts, and making change reviewable, including in AI-assisted workflows.
Definition
Spec-driven development (SDD): write or update a precise description of intended behavior (API contracts, acceptance criteria, data schemas, event contracts, UI states) and use that artifact to drive implementation, tests, and review.
Related / overlapping practices:
| Practice | Relationship |
|---|---|
| API-first / contract-first | OpenAPI/AsyncAPI/Protobuf as the contract |
| TDD | Tests as executable spec; SDD often broader (human + machine readable) |
| BDD | Examples in domain language; can feed specs |
| Design docs / RFCs | Narrative rationale; SDD focuses on normative behavior |
| ADR | Decision record; complements specs |
Why seniors care
| Problem | Spec helps by |
|---|---|
| Ambiguous tickets | Forces inputs/outputs/errors/edge cases |
| Microservice misintegration | Shared contracts + versioning |
| AI-generated code drift | Machine-checkable constraints |
| Review theater | Diff the spec + tests, not only code |
| Knowledge silos | Spec becomes onboarding artifact |
What a good spec contains
For an API/feature, normative sections:
- Purpose / non-goals
- Actors & authZ
- Inputs / outputs — schemas, headers, idempotency
- Invariants & error model — status codes, error codes
- Consistency / side effects — sync vs async; events emitted
- Acceptance scenarios — given/when/then or examples
- SLOs / limits — rate limits, payload sizes
- Observability — metrics, traces, logs fields
- Migration / compatibility — expand-contract plan
Vague adjectives (“fast”, “secure”, “handle scale”) are not a spec until quantified.
Production case study (high volume)
Context: Payments platform launching a new “Capture” API used by hundreds of merchants at millions of captures/day; ticket said “make it reliable and fast.”
Why seniors care: Without normative error codes, idempotency, and SLOs, every team invents incompatible clients; incidents become contract disputes.
Failure / symptom: Merchants disagree on retry behavior; duplicate captures; mobile/web diverge; oncall cannot tell bug vs undefined behavior.
Resolution: Spec PR first — schemas, Idempotency-Key, error model, rate limits, observability fields; review before code; publish OpenAPI as source of truth.
Seen at / similar to: Stripe API versioning discipline; Twilio/GitHub public API specs; Amazon API Gateway + OpenAPI shops.
Typical artifacts
| Artifact | Use |
|---|---|
| OpenAPI / GraphQL schema | HTTP API contract |
| Protobuf / gRPC proto | RPC contract |
| AsyncAPI / Avro / JSON Schema | Events |
| JSON Schema / DB migration plan | Data |
| State diagrams | Lifecycle-heavy domains |
| Executable acceptance tests | Living verification |
| Pact / contract tests | Consumer-driven |
Production case study (high volume)
Context: Event-driven order system (Kafka + Avro) with 20 consumers; producer renamed a field in a “compatible” deploy without registry checks. Why seniors care: Schema breaks poison all consumers at once — blast radius ≫ a single HTTP endpoint; seniors gate compatibility in CI. Failure / symptom: Consumer DLQ flood; lag explosion; mobile push/email pipelines stall during peak. Resolution: Schema Registry BACKWARD/FULL modes; contract tests in CI; expand/contract; canary consumers; treat AsyncAPI/Avro like public API. Seen at / similar to: Confluent/LinkedIn schema discipline; Netflix/Uber event evolution; Shopify Kafka contracts.
Workflow (interview-ready)
Problem → Spec PR (review) → Generate stubs/tests → Implement → Verify vs spec → Version & publish contract
Rules of thumb
- Spec merges before or in the same change set as the first consumer-visible behavior
- Breaking changes require version bump + migration notes
- Generated clients/servers reduce hand-written drift — still review generators’ outputs
Spec-driven + AI-assisted development
Seniors should articulate:
| Do | Don’t |
|---|---|
| Feed specs as constraints to codegen agents | Accept code that contradicts the spec |
| Require tests generated from scenarios | Let the model invent undocumented endpoints |
| Diff against OpenAPI in CI | Treat chat transcript as the contract |
| Keep specs in repo, reviewed | Keep “truth” only in a ticket comment |
Interview angle: Specs improve AI leverage by narrowing the solution space; they don’t remove the need for human judgment on tradeoffs.
Production case study (high volume)
Context: Team used an LLM to “implement the refunds endpoint” from a Slack thread; generated code invented status codes and skipped idempotency; shipped behind a feature flag to 5% traffic. Why seniors care: At high volume, invented contracts cause client breakages and money bugs faster than humans can review prose; specs make AI output checkable. Failure / symptom: Client 4xx/5xx mismatch; duplicate refunds; OpenAPI drift vs running service; AI tests asserted the wrong behavior. Resolution: Feed OpenAPI + acceptance scenarios to codegen; CI fails on spec drift; human review of money paths; chat is never the contract. Seen at / similar to: Industry AI-assist adoption at Stripe/Shopify-scale engineering orgs (process themes); Google/Microsoft API linter cultures.
Java under the hood
| Spec artifact | Java toolchain |
|---|---|
| OpenAPI | openapi-generator / Springdoc → interfaces, models, stubs |
| Protobuf / gRPC | protoc + protobuf-java / gRPC Java stubs |
| JSON Schema / beans | Jackson + Bean Validation (jakarta.validation) as executable constraints |
| Consumer contracts | Pact JVM; Spring Cloud Contract |
| Architecture rules | ArchUnit tests as enforceable “spec” for package/layer deps |
| Events | Avro/Protobuf schemas + Schema Registry compatibility checks in CI |
Generated code is still reviewed; CI should fail on OpenAPI/protobuf breaking changes, not only on unit tests.
Tradeoffs
| Benefit | Cost |
|---|---|
| Clarity & alignment | Upfront time |
| Parallel FE/BE work | Spec churn early on |
| Better test oracles | Over-specification of unknowns |
| Safer evolution | Process can become bureaucracy if every spike needs a novel |
Avoid: writing a 40-page spec for a throwaway spike. Use lightweight specs that grow with certainty.
Compatibility strategies
- Additive changes preferred (new optional fields)
- Explicit versioning (
/v2, package versions, schema registry compatibility modes) - Consumer-driven contracts when many consumers evolve at different speeds
- Feature flags for behavioral rollout after contract publish
Production case study (high volume)
Context: Mobile apps with slow release cadence consumed a gRPC banking API; backend removed a field still read by old apps during a peak payroll week. Why seniors care: Compatibility is an availability property at scale; expand/contract and versioning prevent SEVs that look like “random mobile crashes.” Failure / symptom: Old app versions fail parse; support volume spikes; rollback doesn’t help already-published server. Resolution: Additive fields first; min supported version telemetry; consumer-driven Pact tests; kill switches / feature flags for behavior after contract publish. Seen at / similar to: Stripe API version pins; Google protobuf compatibility rules; Apple App Store slow-client reality for banks.
What interviewers probe
- How do you start a cross-team API? — contract-first story.
- Breaking change process for a public API or event.
- How specs interact with TDD/CI
- Outbox/event schema evolution (link to Kafka).
- Experience with OpenAPI/protobuf — tooling, linting, breaking-change checks.
- When you’d skip heavy SDD — exploration vs platform API.
- AI coding — how you keep generated code honest.
- Production incident caused by spec drift — detection and prevention.
Senior-level expectation: Specs as engineering leverage; proportional ceremony; contract testing awareness; clear ownership of the source of truth.
Pitfalls
- Spec written once then abandoned (“doc rot”)
- Speculating far beyond known requirements
- Multiple conflicting sources of truth (Confluence ≠ repo OpenAPI)
- Generated code committed without review
- Specifying implementation details instead of behavior (over-constrains)
- No error model — happy path only
- AI output accepted without contract/CI gates
- Breaking event fields without registry compatibility checks