General
Every correction I made to my spec added a requirement. The retired rows were still being counted.
Mahiro Hirakawa DEV Community 周榜
1 views
The specification here is append-only. You never edit a row. To change one you retire the old row, which stays in the file under a retired heading, and stand a new row beside it. The old text remains readable, so a reader six months later can see what the rule used to say and why it moved.
Two tools read that file to build the list of requirements the code must satisfy. Neither of them knew what a retired heading was.
So a retire-and-stand produced two live requirements where there had been one. Correcting a row did not fix the specification. It grew it.
The number that should have caught it moved the wrong way
The acceptance check reports how many declared requirements are backed by a test:
dod_rows=263 printed=191/263
Retire one row and stand its replacement, and both sides move:
dod_rows=264 printed=191/264
The denominator grows. The numerator does not, because the retired row names a check that nothing prints any more, which is the entire reason it was retired.
action
requirements
backed by a test
coverage
before
263
191
72.6%
retire one row, stand its replacement
264
191
72.3%
correct ten more rows
274
191
69.7%
Coverage therefore falls slightly every time anyone corrects anything. Nobody reads a one-row drop as a bug. It reads as the ordinary friction of a growing spec, and it points in a direction that discourages exactly the work you want: precision.
Why no reader noticed
Both tools locate requirements by matching a heading pattern. A retired heading matches it, because retiring changes a prefix in the text and not the shape of the line. There was no bug in either reader. There was a concept, "retired", that lived in the writing convention and had never been given to anything that reads.
That is the general shape and it is worth naming: a convention that is not in the data is not a convention, it is a habit. Every reader is free to disagree with it, and they will disagree silently, because each one is behaving exactly as written.
The fix is not a skip
The obvious repair is to teach both readers to skip the retired prefix. I did not do that, for the same reason I would not fix a duplicated constant by copying it a third time.
Instead the heading rule became data: one table saying which heading forms are live, which are retired, and what each one means, with the readers deriving their filter from it.
[[heading]] form = "## R-\d+" status = "live"
[[heading]] form = "## retired_R-\d+" status = "retired"
A third tool, added later, cannot get this wrong by forgetting. It can only get it wrong by not reading the table at all, which is a visible omission rather than a silent divergence.
The check that makes the property hold
The property worth testing is not "retired rows are skipped". It is that retiring is denominator-neutral:
assert: retire one row and stand its replacement
dod_rows before == dod_rows after
printed before == printed after
That check would have failed on the day the convention was invented, long before anyone accumulated corrections. It tests the operation rather than the state, which is what you want for anything append-only, because state grows and operations are the only thing you can pin down.
The same defect, one layer up
The append-only rule exists so that history is never destroyed. The retirement convention exists so that append-only does not mean accumulating contradictions. The readers were built for the first rule and nobody had told them about the second.
Whenever you add a rule that makes an earlier rule survivable, check whether everything that consumed the earlier rule knows about the new one. The second rule is usually written as prose, in a different document, months later, by someone who is thinking about the writing side and not the reading side.
Two things I keep
Retiring a row must not change any count. If correcting something moves your coverage number, the number is measuring your editing activity rather than your code, and the first thing it will teach people is to correct less.
Put the convention in a table the readers load. "We mark these as retired" is a sentence in someone's memory. A heading-form table is a thing a new tool has to read, and its absence is loud.
Read original: https://dev.to/mahirhir/every-correction-i-made-to-my-spec-added-a-requirement-the-retired-rows-were-still-being-counted-111g
← Previous
How to automatically find the batch size when using Accelerate with FSDP2? [D]
Next →
Coming from Java: functions are values in Python
Related
Semantic tag vs Non-Semantic tag
General
5
Dev.to (EN Zone)
How LinkedIn "Bold" Text Actually Works (It's Not Bold At All)
General
5
Dev.to (EN Zone)
Google ADK Callbacks Are a Policy Plane, Not Just Hooks
General
7
DEV Community 周榜
How I Modelled My Power BI Data — Data Modelling, Relationships & Joins (Kenya Crops Dataset)
General
3
DEV Community 周榜
Comments0
No comments yet — be the first