DEV Community

Mahiro Hirakawa
Mahiro Hirakawa

Posted on

Asked whether my tree was coherent, I said yes. The number turned out to be 30 of 55.

Someone asked me a reasonable question: if everything is kept in sync, then whole-tree coherence is guaranteed, right?

I said yes. I had no measurement. When I built one, the answer was no.

OK_REQ_PRINTS  rows=64/64  prints=55  declared=30/55  undeclared=25
               arch_rows=10/10  arch_undeclared=6
Enter fullscreen mode Exit fullscreen mode

The requirement document names 55 checks as the things that decide its rows. Of those 55, twenty-five are declared nowhere in the implementation. The requirement had been naming deciders that do not exist, for as long as anyone had been reading it.

The rule was enforced on one side only

The project has a rule about denominators: they grow only by declared rows. Add a component, declare it, and the count goes up. That rule was enforced, carefully, on the configuration that describes the implementation.

The requirement file is the thing the configuration is supposed to satisfy. Nothing ever counted whether the names it uses exist.

config file   →  every row declared, counted, checked
requirement   →  names 55 deciders, none of them counted
Enter fullscreen mode Exit fullscreen mode

A correspondence has two sides. Enforcing an invariant on one of them feels like enforcing it, because the side you check is always clean.

The 25 are three different problems, and the split is the point

kind count what it means
naming disagreement 15 a spec already carries this exact law, under a different name
no owner at all 7 no component claims this law
pending 3 a queued component will declare them

Fifteen of the twenty-five are not missing work. The law is implemented, checked, and named something else. The requirement says one word, the implementation says another, and both are right about the behaviour.

The temptation is enormous, and it is one command:

$ # 25 -> 10 in a single commit, every rename individually defensible
$ sed -i 's/OK_UNDO_FORWARD/OK_UNDO/; s/OK_VERDICT_RECORD/OK_VERDICTS/; ...' requirement.md
Enter fullscreen mode Exit fullscreen mode

It is the wrong move, because "the spec carries the same law" is a claim, and a bulk rename asserts it fifteen times without checking it once. Some of those pairs will turn out to be two similar laws rather than one, and the rename would erase the only evidence that anyone had looked. Each is resolved by reading the spec row that carries the law and deciding, per name, whether to retire the requirement row onto the declared name or to add the missing row.

The seven with no owner are the real finding, and they were hidden behind the fifteen. A number that mixes "we named it twice" with "nobody built it" is not actionable in either direction.

Where the number lives until it is zero

The 25 sit as a named third value on every run of the architecture check. They are not a failure: nothing is broken, and nothing was decided wrongly. They are also not a pass.

The line is deliberately not in the acceptance gate yet. It goes in when the count is zero, or when every remaining name is a decision someone has to make rather than work someone has to do. Putting it in the gate today would block everything on a number that is mostly bookkeeping, and the first response to a blocking number that is mostly bookkeeping is a bulk rename.

Two things I would keep

When asked whether something holds, check whether you have a number before answering. I did not lie, and I was wrong, and those are not the same failure. "I believe so, and nothing measures it" was available and true.

An invariant enforced on one side of a correspondence is not enforced. The side you check stays clean, the count looks healthy, and the disagreement accumulates entirely in the side you do not.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.