Double-entry bookkeeping
Pacioli's Summa codified the journal and the ledger. Entries are appended, errors are answered by reversing entries, and every balance is derived from the record.
Source · history of double-entry ↗02 · Events · causal ledger · append-only
Every action is an event. Every event provokes a reaction. We keep both, in order, forever, and read the graph between them for the loops nobody designed.
The third law
A row in a table remembers where it ended up. An event log remembers how it got there. In an event-sourced system nothing is overwritten: state is not stored, it is derived, a left fold over everything that has ever happened.
Replay the fold and you get the present. Stop it early and you get the past, exactly. Every reaction carries the id of the action that caused it, so the history is not a list. It is a graph.
state(t) = fold(apply, ∅, events[0 ‥ t]) present = state(now) // rebuilt, never stored past = state(t₀) // exact, not approximate cause(e) = e.causation_id thread(e) = e.correlation_id
Invariants
Events are facts. Facts are never edited, only followed by newer facts.
A causation id and a correlation id on every event. The graph is declared at write time, not guessed at read time.
Projections are disposable. Drop one and replay rebuilds it, bit for bit.
Any aggregate can be read exactly as it stood at any instant, under any version of the code that folds it.
A mistake is answered by an equal and opposite event. Both stay on the record.
A reaction that eventually causes its own cause is a bug, a market or an attack. Either way, it is reported.
Read continuously
A table that is updated in place remembers where things ended up. It does not remember why. Here every event names the event that caused it, so the chain exists the moment the write commits. Pick a question; watch the machine answer it over thirty event types and forty-six recorded causes, and read its reasoning as it goes.
Can this system set itself off, with nobody pressing a button?
Method · Tarjan · strongly connected components · O(V+E). Visit every event once and keep the ones that can each, eventually, cause every other.
Live · this page, since you arrived
Simulated in your browser by the graph at the top of this page. Nothing is sent to us, and nothing is stored.
Downstream
Every balance is a sum you can audit. Every reversal is a fact, not a correction.
Who tasked what, what it set in motion, and in what order. Replayable after the fact.
Rings are cycles. Mule chains are paths. Both are visible the moment the edges exist.
Exploit loops surface as cycles before the economy inflates around them.
In production
The append-only log is older than the computer. The systems below run on it today, at scales most teams will never need. We borrow their invariants, not their headcount.
Pacioli's Summa codified the journal and the ledger. Entries are appended, errors are answered by reversing entries, and every balance is derived from the record.
Source · history of double-entry ↗Around six million orders a second through business logic on one thread, in memory, with no database. State is rebuilt by replaying the input journal; with nightly snapshots a full restart takes under a minute.
Source · Fowler, The LMAX Architecture ↗Every repository is an append-only, content-addressed graph of immutable commits. A branch is a pointer into it. Every developer already works in an event-sourced system.
Source · Git internals, objects ↗Over seven trillion messages a day across more than 100 clusters, 4,000 brokers and roughly seven million partitions. The partitioned log, as infrastructure.
Source · LinkedIn Engineering ↗Workflow state is never stored directly. A crashed worker replays the event history, reuses recorded activity results instead of re-running them, and non-deterministic code is caught on replay.
Source · Temporal docs, event history ↗A database built around one shape of event: the transfer. Each one debits an account and credits another, so total debits equal total credits by construction.
Source · TigerBeetle docs ↗An accumulate-only database in which every fact carries the transaction that asserted it. Nubank built a bank on it, then acquired its makers, Cognitect, in 2020.
Source · Building Nubank ↗