← Software design practices guides

How to compare spec-driven development vs TDD

How-To Software design practices Beginner 1101013HOWTO-1101013

HOWTO-1101013Software design practicesBeginner

This guide shows you how to compare spec-driven development with test-driven development.

TDD and SpecDD both improve design by making intended behavior explicit before or during implementation. They operate at different levels. TDD uses tests to drive and prove behavior. SpecDD uses source-adjacent specs to define the durable contract: purpose, ownership, boundaries, dependencies, required behavior, non-goals, tasks, and completion criteria.

The strongest workflow often uses both. The spec explains what belongs here and why. The tests prove the behavior works.

Short answer

Use SpecDD to define the behavior, authority, and design boundaries. Use TDD to write executable checks that guide implementation and prove the behavior. Specs are not tests, and tests are not specs. Specs preserve intent and scope; tests verify behavior.

When to use this guide

Use this guide when:

The difference

TDD usually starts with a failing test, then implementation, then refactoring. The test is executable. It proves whether behavior works in the tested case.

SpecDD starts with a spec or spec update. The spec is not executable in the same way. It tells humans and agents what the subject owns, what behavior matters, what must not happen, what dependencies matter, and what completion looks like.

That means a test can fail or pass, but a spec can authorize or reject a design direction.

What SpecDD is better at

SpecDD is useful for:

Example:

Spec: Itinerary Validation

Purpose:
  Decide whether an itinerary item can be saved.

Owns:
  ./itinerary-validation.js
  ./itinerary-validation.test.js

Must:
  Reject itinerary items without a place name.

Must not:
  Save itinerary items directly.
  Render UI feedback.

Done when:
  Missing-place validation is covered by a check.

The spec says where validation belongs and what it must not absorb. A test alone usually does not communicate that design boundary.

What TDD is better at

TDD is useful for:

A test derived from the spec might check:

Given the place name is empty, validation fails and no itinerary item is saved.

The test proves the behavior. The spec explains why validation belongs in this unit and why saving must stay elsewhere.

How to combine SpecDD and TDD

1. Write or update the spec

Start with durable behavior and boundaries:

Must:
  Reject itinerary items without a place name.

Must not:
  Save itinerary items directly.

2. Review the spec

Before writing tests, check:

3. Derive tests from the spec

Use Must, Must not, Scenario, Example, Handles, Raises, and Done when to choose tests.

Good test sources:

4. Implement with TDD if useful

Write a failing test for one specified behavior, implement the smallest change that passes, then refactor while staying inside the spec boundary.

5. Review both

During review, ask:

Example workflow

Spec:

Scenario: missing place name
  Given the place name is empty
  When the person adds the itinerary item
  Then validation fails
  And no itinerary item is stored

TDD step:

Write a failing test for missing-place itinerary validation.

Implementation step:

Implement the missing-place itinerary validation behavior.

Review step:

Review the Itinerary Validation change against its spec and checks.

Each prompt names the work in human terms and keeps the action focused.

Common mistakes

How to verify the result

SpecDD and TDD are working together when:

← Software design practices guides