The demo always works. That is the first thing anyone shipping a system like this learns, and usually the most expensive lesson on the schedule.
A demo runs on the happy path — clean input, a forgiving room, someone at the keyboard who knows which button not to press. Production runs on everything else: the malformed upload at two in the morning, the person who pastes a spreadsheet into a field built for a name, the region where the connection drops every ninety seconds and nobody thought to test what happens on the way back up.
The gap nobody puts in the estimate
Teams are good at estimating the part they can picture. The model, the endpoint, the screen. What gets left out is the work that only appears once real people touch the thing:
- Deciding what the system does when it is unsure, rather than when it is wrong.
- Making a failure legible to someone who did not build it.
- Undoing things. Almost nothing ships with a way back.
None of that is glamorous and all of it is load-bearing. The teams that ship well are not the ones with the cleverest architecture; they are the ones who wrote down what happens when it breaks before they had to find out.
Measure the boring number
There is usually one number that decides whether a project is going well, and it is rarely the one on the slide. Not throughput — recovery time. How long between something going wrong and somebody knowing. Everything else is downstream of that.
You do not get judged on your best day. You get judged on how you behave on your worst one, and on whether anyone had to find out from a customer.
A worked example
The shape of the fix is almost always the same: make the failure a value you can pass around instead of an exception you hope someone catches.
async function load(id) {
const res = await fetch(`/api/items/${id}`)
if (!res.ok) {
// A result, not a throw: the caller decides what the reader sees.
return { ok: false, status: res.status }
}
return { ok: true, data: await res.json() }
}It is not a clever change. It moves one decision from the place that cannot make it — deep in a helper, with no idea what screen it is on — to the place that can.
What to take away
Start with the failure, not the feature.
Write the error state first and the happy path second. The order sounds pedantic and it changes the design more than any framework choice will. By the time you get to the part everyone was excited about, the hard questions are already answered — and the demo, when you finally give it, is the same code the customers are running.
Praesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.
Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero. Nullam sit amet turpis elementum ligula vehicula consequat. Morbi a ipsum. Integer a nibh.
In sagittis dui vel nisl. Duis ac nibh. Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus. Suspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.