Evidence Before Abstraction
Duplication proves demand, not design.
Overview
An abstraction is justified by a second consumer that has actually used it, not by a second occurrence of a shape. Until then it is a prediction wearing a package's clothing.
Why
Extracting a shared foundation feels like progress because it produces artifacts: packages, types, documentation. None of that is evidence. Two identical files mean you are paying for a copy; they do not mean the copy is correct, and extracting one implementation's fork canonises its accidents alongside its insights. The failure is asymmetric, which is what makes it worth a principle. A duplication left in place costs a second edit. An abstraction extracted too early costs a version boundary, an install decision, a release cadence, a migration path, and a shape every future consumer must either accept or route around, and it does all of that while looking like the disciplined choice.
Standard
Extract when a written abstraction gains its second consumer, not when the shape appears twice. A second consumer counts only once it has actually resolved and executed the shared code; a copy, an independently compatible implementation, or a stale build is evidence of duplication or of design validation, but not of adoption. Ask two questions separately. Is the design right?, answered by trying to adopt it. Was it adopted?, answered by counting consumers. Collapsing them into one question deletes good abstractions and preserves bad ones. Record what you decided not to extract, and why, so the question is not re-litigated.
What This Forbids
- Extraction on symmetry, "we have five of these, so we need a sixth"
- Extraction on forecast
- A package created because a domain exists rather than because a consumer is waiting
- Counting packages, types or documents as progress
Examples
- Four independent implementations of one file-validation routine accumulated across a family of projects, around 617 lines doing a single job. That is duplication with a measured cost, and the correct trigger for extraction.
- Two products independently converged on representing audit actions as plain constants rather than database enum types, so a new action never requires a migration. Independent convergence is the strongest evidence available, and rarer than it sounds.
- Six extraction candidates were examined and rejected with written reasons. One turned out not to be duplication at all, but two contradictory designs, and the consuming product's design was the stronger of the two.
- An operator command-line tool was built twice, seven weeks apart, in two products, without a shared core. Two implementations normally satisfy the second-consumer test; because neither was built against a shared abstraction, the shape had still never been validated as one.
Counter Examples
- A shared package built, tested, documented and released with zero consumers. It carried a manifest, a build step, a version, a release cadence and an install decision, more distribution surface than code.
- Nine packages extracted in a single day, before a consumer existed for most of them. Eleven of the twelve most valuable subsystems in that codebase were written afterwards, so the extraction captured whichever half of the architecture happened to exist first.
- A proposal to split a framework into roughly twenty-five packages, later retracted by its own author: splitting on subject matter multiplies version boundaries, while dependency weight is the only split a consumer can actually feel.
Lessons Learned
- Zero consumers is evidence that adoption failed, not that the design is wrong. The two questions are independent and must be asked separately.
- The strongest validation available is not adoption. It is a design being confirmed correct by a consumer that never used it, because it turned out to fit a need that consumer had solved differently and never reported.
- Adoption may increase total code. One migration removed around 145 lines of duplication and added around 550 of declaration; the payoff was one authority per rule and four latent defects surfaced, not a smaller codebase.
- A shared component whose adoption reduces a consumer's existing safety has an adoption problem no documentation will fix.
- Write down what you did not extract and why. A rejection without a recorded reason gets re-proposed every few months.
Learned From
- ZothKitA framework extracted from the newest codebase rather than the most hardened one, before most of what was worth extracting had been written, and a package that shipped complete with no consumer at all.
- JinaraThe one product that adopted the shared foundation, and still reimplemented two of its modules, the most informative signal the framework produced.
- AtlasFour months of patterns invented and never extracted, surviving only because another project copied the files by hand.
Related Principles· 2
Related Documents· 2
Referenced By· 7
Version History
- v0.1.0
Established from the cost of extracting a shared foundation before the evidence for it existed.