Skip to content
BuddingConcept

Desiderata in Tension

planted Jul 20, 2026 · last tended Jul 20, 2026

A flat list of eleven properties hides the fact that they interact. Beck was explicit that he does not hold them simultaneously and offers no priority order: which properties you optimize is a per-context call, because pushing on one often costs you another. So the list has an internal structure worth naming: where the properties reinforce each other, and where they collide.

Reinforcing

These pairs pull the same direction. Most are already asserted in the notes themselves; collected here they show that a single move often buys two properties at once.

  • Minimal Data → Fast and Readable: the smallest fixture is both quicker to build and easier to read, because there is no irrelevant data to wade through.
  • Readable → Diagnosable: readability is what diagnosability degrades into at failure time; an unreadable test that fails tells you nothing.
  • Run in Any Order → Diagnosable: a cascade of collateral failures from one broken fixture diagnoses nothing, so order independence is a precondition for one-defect-one-failure.
  • Behavioral + Structure-Insensitive: the mirror pair. Testing through the observable contract buys both at once: notice what a caller can see, ignore everything a refactor may change.
  • Composable → Fast: composing confidence from small focused slices is what lets a fast suite stand in for the slow, exhaustive enumeration it never runs.

Trade-offs

These pairs pull against each other. You resolve each one by context, and in most cases the lever is a mechanism (doubles, real collaborators, seams) that the property list deliberately leaves off its own axis; the tension between the properties is real regardless of how you resolve it.

  • Fast ↔ Behavioral: the pyramid trade-off. Tests that resemble real usage exercise real collaborators and real I/O, which is slow; fast tests lean on doubles that drift from how the software is actually used.
  • Deterministic ↔ Behavioral: the clock, the network, and concurrency are how software really runs and also among the main sources of flakiness. Stubbing them buys determinism at the cost of fidelity (Fowler counts the clock, remote services, and asynchrony among his sources of flakiness).
  • Writable ↔ Structure-Insensitive: mocking every collaborator makes a test trivial to write but couples it to the call structure, so a behavior-preserving refactor breaks it. This is why Writable is a gauge, not a lever: cheap-to-write bought by coupling is the design telling you something.
  • Structure-Insensitive ↔ Diagnosable: a test that ignores internals fails over a broad surface, so it localizes the defect poorly; a sharply diagnosable test often pins closer to the structure it is meant to ignore.
  • Composable ↔ Behavioral: covering each dimension of variability in its own isolated slice trades away the end-to-end fidelity of exercising them together. The mockist and classicist camps divide on exactly this tradeoff.

The axis most trade-offs cross

Four of the five trade-offs route through one property: Behavioral, fidelity to real usage. Fast, Deterministic, Composable, and mock-driven Writable each buy their gains by moving execution away from production-like conditions. That is the concrete shape of Beck’s point that you cannot maximize them all: the more your suite trades toward speed, stability, isolation, or ease of authoring, the further it drifts from the one property whose whole job is to resemble production. Where the balance sits is a context call, which is the testing a green suite can never automate.

Part of Test Desiderata.

Sources