A traffic light, a TCP connection, a payment transaction, and a hiring process are all state machines. Draw the states. Draw the transitions. The failure modes become obvious.
Most engineers meet finite automata once, in a theory course, and file them away as academic. They then spend the rest of their careers building systems that remember things between requests. Every such system is a state machine. Naming it as one is the difference between a design that behaves and a design that produces impossible states in production.
This article traces T7 — State Machines from its theoretical root to its distributed form. The shape is identical at every layer. The stakes rise with each level.
Level 1 — The theoretical root: finite automata
A finite state machine has three parts. A defined set of states. A set of inputs, called transitions. Rules that say which state to move to on each input.
Only valid transitions are allowed. That is the entire idea. The machine cannot invent a transition that is not in the rules. It cannot land in a state that is not in the set.
This is T7 in its simplest form. In theory it is a regex engine — a deterministic finite automaton that reads a character and moves to the next state. Every position in the input string is a state. Every character is a transition. The regex either terminates in an accepting state or it does not.
The tradeoff is AT7 — Automation vs Control. The state machine automates decisions. It removes the ability to handle a case that the rules do not cover. What the machine gains in predictability, it loses in flexibility. You cannot patch a running transition on the fly.
Level 2 — The systems form: TCP connection lifecycle
The same idea leaves the textbook and enters the network stack. A TCP connection has states — SYN_SENT, ESTABLISHED, CLOSE_WAIT — and defined transitions between them. A packet arrives. The connection moves to the next state or the packet is rejected.
The shape is identical to the regex DFA. The stakes are not.
At the theoretical layer, an invalid transition means the string is not accepted. At the network layer, an invalid transition means a socket stuck in CLOSE_WAIT for hours. It means a leaked file descriptor. It means the process eventually cannot accept new connections.
The state machine is still doing exactly what it was defined to do. The failure is that some transitions were never wired to a cleanup path. States that should be terminal become terminal in the wrong way.
This is where FM4 — Data Consistency Failure first appears. The kernel and the application disagree on the connection's state. Both are looking at their own state machine. Neither is wrong on its own terms. The system as a whole is inconsistent.
Level 3 — The application form: order and trip lifecycles
Move up one more layer. A retail order moves through PENDING → CONFIRMED → SHIPPED → DELIVERED. A ride-hail trip moves through REQUESTED → MATCHED → IN_PROGRESS → COMPLETED. An authentication session has ACTIVE, EXPIRED, and REVOKED.
Every one of these is T7. The engineer who writes it as a set of boolean flags — is_confirmed, is_shipped, is_delivered — is building a state machine without naming it. The rules for which flag combinations are legal live in comments, in tribal knowledge, in a Jira ticket somewhere.
The failure mode is guaranteed. Sooner or later, a code path sets is_delivered = true on an order where is_shipped = false. The database now holds a state the business rules do not permit. Support tickets follow. A migration is written to detect and repair the impossible rows.
Naming the states and drawing the transitions prevents this. A transition function that rejects PENDING → DELIVERED cannot be bypassed by a careless code path. The state machine is a constraint enforced by construction, not by convention.
The tradeoff is still AT7. The rigid state machine refuses valid business cases the designers did not anticipate — the customer service rep who needs to force an order from PENDING to REFUNDED without shipping. Automation buys correctness. It sells flexibility.
Level 4 — The event-sourced form: state as accumulated log
Event sourcing makes the state machine explicit by storing the transitions rather than the current state. The current state is a function of the event log. It can always be reconstructed by replaying events from the beginning.
This inverts the usual pattern. A conventional application writes the current state to a database row and overwrites it on every transition. An event-sourced application writes only the transitions, in order, forever. The state is derived.
Three properties fall out of this inversion. Audit is free — every transition is on the log. Time travel is free — replay the log up to any timestamp to see the state at that moment. Correction is possible — replay the events through a fixed state machine to produce a corrected state.
The cost is that projections must be rebuilt when the state machine changes. If you add a new state or restructure a transition, every read view that was derived from the old machine must be regenerated from the event log. On large logs this is slow and operationally expensive.
CQRS — Command Query Responsibility Segregation — is the natural partner. The write side accepts commands and appends events. The read side maintains projections optimised for queries. The two representations of state serve different access patterns from the same underlying log.
This is where T5 × T7 becomes unavoidable. Caches are state. Every projection is a cache of the event log. When the state machine transitions, every cache derived from that state must be invalidated. Forgetting this is how stale data produces wrong answers.
Level 5 — The distributed form: replicated state machines
Push T7 across a network and it meets T9 — Consensus.
Distributed state machine replication is the core idea behind Raft. Every replica runs the same state machine. The consensus protocol ensures they apply the same commands in the same order. Agreement on the log is agreement on the state.
The insight is exact. If two machines start in the same state and apply the same sequence of transitions, they end in the same state. Replication reduces to log ordering. Ordering reduces to consensus.
FM4 — Data Consistency Failure is the mode this design exists to prevent. Without ordered agreement, two replicas can apply the same commands in different orders and land in different states. Both are internally consistent. Both disagree. The system has no single truth.
Raft trades availability — the leader is a bottleneck and a single point of failure until re-election completes — for the property that all replicas share one state machine's history. The tradeoff is AT7 again at a different scale. The consensus protocol takes control away from any individual node.
Level 6 — The pattern in control flow: circuit breakers and retries
T7 × T11 closes the loop. Feedback loops are often state machines driven by measured signals.
A circuit breaker is a state machine with three states — CLOSED, OPEN, HALF-OPEN. The transition from CLOSED to OPEN fires when the error rate crosses a threshold. The transition from OPEN to HALF-OPEN fires when a timeout expires. The transition from HALF-OPEN back to CLOSED fires when a probe request succeeds.
Retry with backoff is the same shape. The retry delay is a function of the failure count. Each failure moves the state forward. Each success resets it.
What changes at each level is not the pattern. It is the source of the transition signal. At the theoretical layer, the input is a character. At the network layer, a packet. At the application layer, a user action. At the distributed layer, a consensus decision. At the control layer, a metric.
The state machine is the same object throughout. The stakes rise because the wrong transition costs more.
The signal that tells you this applies to your system
You have a database row with multiple boolean flags describing status. You have code paths that check three flags before deciding what to do. You have found orders, sessions, or jobs in impossible flag combinations at least once.
That is a state machine you have not drawn. Every one of those flag combinations is a state. Every code path that mutates a flag is a transition. The rules are not written down. They live in review comments and post-incident tickets.
Draw the diagram. Enumerate the states. List the legal transitions. The impossible states disappear because the transition function refuses them.
The full framework treatment — compression blocks, three-level exercises, and the complete AT/FM mapping — is in the Reference Book, Chapter 3 (The Twelve Threads). Free chapter available at computingseries.com/books/ref.