Learn · Hidden Machines · Part I
budding
A Refactor Must Say What Stays the Same
Carriers, laws, observations, and equality domains.
You will recover algebraic laws from repeated operations, define behavioral equivalence relative to observations, and distinguish source, semantic, canonical, and observational equality.
The route can change while arrival stays fixed
Suppose a parser rewrite returns the same values for every accepted input. One version reports the first error; the other reports all errors. Are they equivalent? For a caller observing only successful values, yes. For an editor displaying diagnostics, no.
A characterization test begins by declaring the observation function. It may record returned values, typed diagnostics, emitted commands, and order. The old and new implementations are equivalent for the refactor when those traces match over the admitted inputs.
Laws name reusable regularity
An abstraction is not made mathematical by wrapping functions in a class. Look instead for a carrier, closed operations, and equations the behavior uses. Combining tree summaries, for example, may rely on an identity and associativity:
In words: an empty summary changes nothing, and regrouping does not change the answer. Associativity permits chunking and tree-shaped evaluation. It does not permit reordering. A counterexample is subtraction: regrouping 10 - 3 - 2 changes the result.
Property tests can quantify over many generated values, but the law must be stated first. Otherwise the generator merely sprays examples at an unnamed promise.
Equal for which purpose?
Two source strings may differ while parsing to the same value. Two values may be semantically equal while occupying different objects. A canonicalizer may choose one representative so semantic equality can become identity. A UI may consider two states observationally equal when they render the same pixels, even though a persistence layer must distinguish them.
Each relation answers a different question:
- source equality: are the encodings identical?
- semantic equality: do they mean the same thing?
- canonical identity: did normalization choose the same representative?
- observational equivalence: can the admitted observer tell them apart?
Using one relation for every layer produces cache misses at one boundary and destructive deduplication at another.
Where the model stops
Do not demand preservation of every incidental fact. If object addresses are not public observations, a persistent rewrite may change them. Conversely, do not hide a real promise by narrowing the test after the fact. The observation set is part of the contract and should be decided before the rewrite.
Lessons
- Carrier, operation, and used laws make regularity explicit.
- Equivalence is always relative to declared observations.
- Passing tests cannot prove properties the tests do not observe.
- Equality domains should be named at their boundaries.
Practice
- State identity and associativity in words without notation.
- Decide whether a stable-sort rewrite must preserve the order of equal keys.
- Define the observation trace for replacing a retry loop while preserving externally visible behavior.
The next chapter turns these pieces into a repeatable recovery procedure.
References
- “John C. Reynolds, “Types, Abstraction and Parametric Polymorphism”.” IFIP Congress, 1983. — foundational context for reasoning about observable behavior across representations.
- “fast-check documentation, “Properties”.” — executable universal properties over generated cases.