"Show the user's recommendations" is a sentence with an obvious happy path and no stated opinion about what happens when the recommendation service is down, slow, or returns nothing. Most of our worst production embarrassments have come from that gap, not from the happy path being wrong.
Degradation is a design decision, not an accident
If nobody decides what a component does under partial failure, the component decides for itself, usually by throwing an unhandled error at the least convenient layer of the stack. That is not a bug in the strict sense — it is a decision nobody made, showing up as a stack trace instead of a specification.
What we now ask for every non-trivial feature
- What does the user see if this is slow? A spinner has an implicit timeout; name it.
- What does the user see if this fails entirely? Ideally something, rather than a blank space where a feature used to be.
- What does the user see if this returns nothing valid? Empty is not the same as broken, and conflating them teaches users to distrust a working feature.
- Does the rest of the page still function? A failed widget should not be able to take down a page it shares with three working ones.
A concrete example
The recommendations panel above now has a written, tested behaviour: if the service does not respond within eight hundred milliseconds, the panel shows a fixed, cached fallback set rather than a spinner, and logs the timeout for the team without troubling the user with it. That took one extra line in the ticket and roughly a day of engineering. The alternative — no answer to the question — cost us a very visible blank rectangle on a client's homepage for six hours last year.
A happy-path specification describes a feature that has never met the internet. Everything meets the internet eventually.
Where this shows up in review
We now ask for the degraded-path test before we ask for the happy-path test in review, because it is the one people forget to write and the one most likely to be discovered by a user rather than a colleague.
The trade-off worth naming
Specifying every degradation path in full detail is its own kind of waste for low-stakes features — a decorative widget that quietly fails need not have the same rigour as a checkout step. Judging which is which is the actual skill; the checklist just makes sure the judgement gets applied on purpose rather than by accident.
