State & State Machines

Making lifecycle explicit, so that invalid transitions become impossible to express rather than merely undesirable — and boolean-flag explosion becomes visible.

Explicit State
▶ lab

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.

Q · The lifecycle of this object is currently derived from four timestamps and two flags. What do I gain by naming the states instead?
State Machines
▶ lab

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.

Q · How do I express a lifecycle so that the legal moves, their preconditions and their side effects are all visible in one place?
Invalid Transitions
▶ lab

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.

Q · How do I make an illegal lifecycle move impossible rather than merely discouraged, and how do I record why it is illegal?
Boolean Flag Explosion
▶ lab

Four independent booleans describe sixteen states. Five are legal. The other eleven are not prevented by anything, and the arithmetic is the whole argument.

Q · My object has `isPaid`, `isCancelled`, `isShipped` and `isRefunded`. How many states does that actually create, and how many of them did anyone design?
State Ownership

Which module is allowed to mutate this piece of domain state — and what it means that the answer is currently "any of them".

Q · Six modules can write this field. Which one is responsible for it being correct, and how would anyone tell?
Making Illegal States Unrepresentable

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.

Q · This combination of values is always a bug. Can I shape the type so it cannot be written, and is that worth what the shape costs?
Optional Values and Absence

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.

Q · This value may not be there. How do I say that so a caller cannot forget, and what do I do in a language that will not let me?