Your demo never crashes at the wrong moment
Not long ago I read the code of an app I’d built, properly, for the first time. I’d shipped most of it fast, with AI writing a lot of it, and it demo’ed well. What I was looking for was the opposite of a demo: what does this thing do when nobody’s watching?
It did two things I never wanted it to. They’re the two things software is least allowed to get wrong:
- make a promise
- do a money operation
That gap has a simple cause. A demo is a performance, and nothing fails at the wrong moment, because in a demo there is no “wrong moment.” You click, it works, and everyone nods. Production is the same feature with one difference: the wrong moment is always available.
The deadline nobody was there for
The app runs auctions. Each one has a deadline. When the deadline passes, the auction closes, a winner is picked, and the winner gets an email.
Here’s how it actually worked:
In a demo, there’s always a visitor. It’s me, clicking. So it always closed on time, every time.
Now picture a real auction that ends at 2am, on a quiet lot nobody’s watching. The deadline passes. Nothing opens the page. So nothing closes the auction, nothing picks the winner, and the winner is never told they won. The result just doesn’t happen.
The software was counting on a person being there. Real-time systems can’t count on that. The missing piece is a clock that fires on its own, on time, whether or not a single person is watching.
The charge with no record
Now, to the money operation.
When a customer pays, two things have to happen: the card gets charged, and my app writes down that it charged them. Easy, right? Charge, then record.
They run one after the other, which means there’s a sliver of time between them.
If the app crashes in that moment, after the charge but before the record, the customer has paid real money and my app has no memory of it. No receipt on my side. Nothing that says “this person is owed something.” And nothing goes back later to notice the gap and fix it. The money left their account, and nothing on my side ever knew.
In a demo, the two steps run a millisecond apart and nothing ever crashes in between. Why would it? The whole thing takes a blink. But run it ten thousand times, on real hardware that restarts and drops connections, and that blink is where a customer gets charged for nothing.
Why you never see these coming
Both gaps share a similarity. They only appear at the moment between two steps, or the moment when nobody’s there. A demo is built entirely out of the good moments. You show the click and the result. You never show the 2am, and you never crash the app on purpose halfway through a payment.
So the feature looks finished. It does the thing. It just doesn’t do the thing when the thing is finally battle-tested, and that version is supposed to be the one production runs.
That’s the real distance between “it works in the demo” and “it works.” It’s the same features, made to survive the worst moment instead of only the rehearsed one.
Make the wrong moment happen on purpose
So how do you battle-test a feature before a real customer ever touches it? You stop waiting for the wrong moment and go make it happen yourself.
That’s what an end-to-end test is for. A unit test checks one function on its own. An end-to-end test (e2e for short) drives the whole app the way a real user would: it opens the page, clicks the button, pays the money, and checks what actually happened at the end. It’s the closest thing to production you can run before production.
The powerful part is that inside a test, you control the world. So you can script the exact moments a demo skips:
- Let the auction deadline pass with nobody on the page, then check a winner was still picked and emailed.
- Kill the app in the microseconds between the charge and the record, restart it, and check the customer isn’t left paying for nothing.
- Run the whole payment flow ten thousand times, and check it never once charges twice.
Each of those is a test you write once, and it runs on every change you make from then on. It’s a demo you’re allowed to break, on purpose, in private, before it’s real money.
A demo asks “does it work?” A real e2e suite asks: “does it still work when the thing goes wrong?” Production is going to ask you that question no matter what. Far better to ask it yourself first, in a test, than to hear it from a customer at 2am.
The two rules under both
If I had to boil it down to something I can carry to the next build, it’s two plain rules:
Don’t lose state. If a result is supposed to happen, something has to make it happen on its own, on time, without a person needing to be there to trigger it.
Don’t drop it, and don’t do it twice. When an action changes the real world (like a charge or a payout), the act and the record of it have to move together, and something has to reconcile them if they ever drift apart. Reconcile just means: go back, compare the two, and fix the gap.
These are some of the exact scenarios that allow software engineers to still have a job. The average vibe-coder would not think of edge cases like this.
What the demo hides
The demo gave me a fast, clean version of the feature that let me see it work and believe in it. But the demo only ever runs the perfect scenario, and it quietly let me believe the best-case scenario was the whole feature. It isn’t. The feature is the good moment plus every wrong one.
Closing that gap is slow, unglamorous work that no demo will ever show you. It’s also the only work that decides whether the thing survives a real customer at 2am.
Changes to this post
Published.
Get the next one straight to email. Free.
No trackers. One email when there's a new post, nothing else. Unsubscribe anytime.