Make your unhappy path sublime
A practical, cross-stack guide to designing software that fails well — for both front end and back end developers.
Chapters #
- Failure Modes — naming the ways systems break.
- Whose Fault Is It Anyway? — classifying errors by who owns them and who can act.
- Failing by Design — making failure part of the design, not a chore at the end.
- Boundaries & Transactions — how errors force you to carve the system and keep it atomic.
- Error Handling Without Fear — representing, propagating, and responding to errors without panic.
- Do or Do Not. Then Retry. — retrying safely without making things worse.
- Keep Informed and Carry On — preserving user agency when things break.
- Writing Insanely Great Error Messages — talking to a frustrated human, well.
- Test Once, Measure Always — proving failure behavior in tests and watching it in production.
Why this book #
Failure is not the exception in software — it is the default state of any system exposed to the real world. Networks drop, disks fill, users do the unexpected, and dependencies disappear. This book is about building software that expects failure and stays trustworthy when it happens.
There's a particular frustration that motivated this book: tutorial code almost always leaves out the error handling. Every example fetches the data, parses the response, and moves on — no timeouts, no retries, no "what if this is null," no failure states. Authors do it because it's easier to teach and easier to read, and the happy path is genuinely all you need to explain the idea.
But real code isn't the happy path. And error handling is remarkably hard to retrofit into code that was only ever designed to succeed. The control flow, the data shapes, and the assumptions all have to change once you admit that any step might fail. You can't just sprinkle it on at the end.
What makes this doubly unfair is that the error-handling code is often the subtlest, most consequential code you'll write — the part that decides whether a glitch becomes a graceful recovery or a silent corruption. It's exactly the code you most want to get right, and exactly the code the tutorials skipped. This book is an attempt to put it back.
What good looks like #
The best apps make failure feel like a normal part of the experience. Watch what YouTube does when your connection drops mid-video: it doesn't throw up a dead player or a stack trace. It pauses, tells you it's trying to reconnect, keeps what you've already buffered, and quietly resumes the moment the network returns. Netflix is just as good — it adapts quality to the connection, holds your place, and recovers without making you start over.
That's the whole philosophy in miniature. These teams put in the extra effort to recover rather than surrender. They treat disconnection as a usual part of the experience, not an exception to sweep under the rug. In practice that means three things, and they're a good rubric for any feature you build:
- Anticipate the failure states. Think through what can go wrong before it does — the dropped connection, the slow response, the half-finished upload. This is the work of Failure Modes and Test Once, Measure Always.
- Keep the user informed. Say what's happening and what, if anything, they can do about it. A clear "Reconnecting..." beats a frozen screen every time. See Keep Informed and Carry On and Writing Insanely Great Error Messages.
- Get out of the way when it's working. Recovery should be invisible on the way back. The moment things are healthy again, the messaging disappears and the experience just continues. This is the heart of Keep Informed and Carry On, supported by Do or Do Not. Then Retry..
Most software gets none of these right. The goal of this book is to make all three feel routine.