State & State Machines
Making lifecycle explicit, so that invalid transitions become impossible to express rather than merely undesirable — and boolean-flag explosion becomes visible.
Name the states a thing can be in instead of inferring them from combinations of fields. The inference is a rule, and an unwritten rule is enforced by memory.
States, transitions, guards and effects as a table the code reads — so the lifecycle is data you can review rather than control flow you have to reconstruct.
The moves that must not exist are part of the design. A comment saying "do not cancel after delivery" is a hope; a transition table that has no such row is a rule.
Four independent booleans describe sixteen states. Five are legal. The other eleven are not prevented by anything, and the arithmetic is the whole argument.
Which module is allowed to mutate this piece of domain state — and what it means that the answer is currently "any of them".
A model where `status = "paid"` with `paidAt = null` cannot be written at all. Powerful where an invariant justifies it — and easy to overdo on a model that has no such invariant.
Say "this may be missing" in the type where the language supports it, and never encode absence as an empty string, a zero, a sentinel date or a magic id.