The weekly letter from Systems Thinking Lab: systems thinking insights for junior engineers, framed through the seven building blocks.
Two strangers bought the same seat. Not seats near each other. The same seat. Row 14, seat 7, sold twice in the same second, to two people who have never met, and both of them are holding a confirmation email that says it is theirs.
Here is how a system gets there. Picture the site selling tickets for an arena show, and picture yourself as the engineer who built the part that sells the seats. The design is the obvious one: a seats table in the database, one row per seat, with a status column. When a buyer clicks Buy, your code checks the row. Is the status open? If yes, charge the card and mark the seat sold. If no, show "seat taken." It reads cleanly. It passes every test. It works every time you click through it yourself.
Then Friday at 10 AM arrives and the tickets go live. Ten thousand people are on the seat map at the same moment, and two of them click row 14, seat 7, inside the same tenth of a second. Buyer one's request reads the row: open. Buyer two's request reads the row a few milliseconds later, before buyer one's update has landed: still open. Both requests pass the check. Both charge a card. Both write sold, the second landing quietly on top of the first. Both buyers get the email. Your code did not misfire once. It did exactly what you wrote, twice.
The failure costs nothing for three weeks. Then the show happens. Two people walk up to row 14, seat 7, each holding a ticket that looks completely real, and an usher gets to decide which one of them paid for a seat that exists. Behind that moment is a support queue, a refund, an apology email, and a buyer who will never quite trust the site again. The worst part is that nothing in your logs looks broken. Every request came back a success. The system never went down. It just quietly promised the same thing to two people.
Look at where the failure lives. It is not in the check, which was correct, and not in the write, which was also correct. It is in the gap between them. Your code checked the seat at one moment and claimed it at a slightly later moment, and treated the world as if nothing could happen in between. On a quiet Tuesday, nothing does. During an on-sale, that gap is a door, and ten thousand simultaneous buyers means somebody walks through it.
The way out is not to make the gap smaller. It is to hand the job to the one layer that can make the gap not exist. That layer is the Relational Database, and the tool is called a constraint: a rule you declare about what is allowed to be true in your data, which the database enforces at the moment of every write, inside the write itself. To use one here, change the shape of the sale. Selling a seat stops being an edit to a status field and becomes the creation of a claim: buying inserts a row into a tickets table, and the rule you declare says no two rows may ever name the same seat for the same show. Now when two claims race for row 14, seat 7, the database lets the first one through and refuses the second at the instant it tries to land. There is no check at one moment and claim at another. The check is the claim. Your code's job shrinks to catching the refusal and telling buyer two, "that seat just went."
Notice what actually happened to the collision. It did not disappear. Ten thousand people still clicked at once, and two of them still wanted the same seat. The collision moved down a layer, out of your application code and into the database, which is the one place every claim must pass through, and which resolves competing writes to the same data by lining them up and taking them one at a time. Refereeing simultaneous claims on shared data is not a feature the Relational Database happens to have. It is a large part of what the block is for.
Once you see the shape, you will find it everywhere. Two people signing up for the same username in the same second: the designs that survive it put exactly this rule on the username column, which is why the second person sees "already taken" instead of two accounts existing. A flash drop where the last hoodie in stock sells to two carts. Two meetings landing in the same room at 2 PM. Anywhere a design checks first and writes second, across a gap, two actors can pass the same check before either write lands.
Now watch the fix that gets reached for first, because it is the wrong one: keep the check in application code and reinforce it. Check the seat again right before the write. Add a background job that sweeps for double-sold seats. Hold a lock in your server's memory while the purchase runs. Every one of these feels like defense, and every one of them is another racer. Your application does not run as one copy. It runs on several servers at once, each running the same checks, and no copy can see what another copy is about to write. Doubling the checks doubles the checkers, and the checkers are the thing that races. More checking makes the gap shorter. Application code cannot make it zero. At on-sale traffic, shorter still loses.
The database can make it zero, because for any one seat it is one place, taking one write at a time. That is the whole trick. Not smarter checking. One referee.
In Course 1 I teach the Relational Database as one of the seven building blocks. Every block earns its place by doing a job the others cannot. Refusing the second claim is this one's.
You do not close the gap by checking faster. You close it by making the check and the claim one move.
P.S. The constraint is one reason the Relational Database earns its spot among the storage blocks. The free walkthrough of the three storage extremes, what each one is built to maximize and what each gives up, is at https://systemthinkinglab.ai/learn/building-blocks/storage-extremes/