Laws as Design Tools
"Write equations, not just examples — laws find bugs nothing else catches."
Every meaningful abstraction has laws — equations that any correct implementation must satisfy. Writing these down and expressing them as property-based tests is the most powerful verification technique in software. Laws catch bugs that types, code review, and hand-written tests all miss — including bugs that cause deadlocks and race conditions.
Physics. F = ma is not documentation — it's a constraint. Any physical model that violates it is wrong, period. Software laws work identically: if your map implementation violates map(x)(identity) === x, your implementation is wrong regardless of whether your unit tests pass. Laws are executable specifications, not suggestions.
import fc from 'fast-check';
// FUNCTOR LAWS — any correct functor must satisfy both
// Law 1: map with identity must change nothing
test('functor: identity law', () => {
fc.assert(fc.property(fc.array(fc.integer()), arr => {
const result = arr.map(x => x);
return JSON.stringify(result) === JSON.stringify(arr);
}));
});
// Law 2: two maps must equal one map with composed functions
test('functor: composition law', () => {
const double = (x: number) => x * 2;
const addOne = (x: number) => x + 1;
fc.assert(fc.property(fc.array(fc.integer()), arr => {
const twoMaps = arr.map(double).map(addOne);
const oneMap = arr.map(x => addOne(double(x)));
return JSON.stringify(twoMaps) === JSON.stringify(oneMap);
}));
});
// THE DEADLOCK THE BOOK FOUND WITH LAWS:
// Law: fork(computation) should equal computation
// (forking shouldn't change the result)
//
// Writing this law and testing it revealed:
// If fork blocks a thread waiting for a result,
// and the thread pool has exactly 1 thread,
// the thread is blocked waiting for itself → DEADLOCK
//
// This bug was invisible to: code review, unit tests, type checking.
// Only the law test exposed it by generating the edge case.
// ROUND-TRIP LAW — serialize/deserialize must be inverses
test('JSON round-trip law', () => {
fc.assert(fc.property(fc.jsonValue(), data => {
return JSON.stringify(JSON.parse(JSON.stringify(data)))
=== JSON.stringify(data);
}));
});