Sorry for the Inconvenience: What National Rail Knows About Failing Gracefully
Photo: UK railway station departure board with cancelled trains, via c8.alamy.com
Stand on any platform at Clapham Junction and you'll see it: a service cancelled, a board flashing revised times, and forty thousand people still getting where they need to be. It's not luck. It's decades of learning to fail in front of the public without the whole thing collapsing into a shambles.
Now compare that to the last time a third-party API went down and took your checkout with it. Somewhere between those two experiences is a lesson about graceful degradation that most of us skipped.
The Announcements Do the Heavy Lifting
The genius of British rail isn't that trains run on time. It's that when they don't, the system tells you — loudly, early, and with an apology attached. The information is degraded, not the service itself. You can still buy a ticket, still reach the platform, still make a decision.
Contrast that with the typical web app failure mode: a spinner, a timeout, then a generic 500 page that tells the user precisely nothing. The service hasn't just failed — it's failed uselessly.
TfL's open data API is a good model here. Hit the disruption endpoints and you get structured, machine-readable honesty: which lines are broken, why, and what the alternatives are. The API doesn't pretend everything is fine when it isn't. That's the first pattern worth stealing.
Pattern One: Fail Loudly, Not Silently
The worst failures are the quiet ones. A downstream service starts returning empty arrays instead of errors, and your system happily displays blank search results for three days before anyone notices. By then, someone's lost a sale, a booking, or a hospital appointment.
Build the equivalent of the tannoy announcement:
- Explicit health signals. If a dependency is degraded, surface that in your own status, not just in a log file nobody reads.
- Distinguish empty from broken. A zero-result response from a partner API should trip an alert, not render as a quiet Tuesday.
- Apologise honestly. "We're having trouble fetching your data — some information may be out of date" beats a blank screen every time.
The rail industry learned this the hard way. A silent failure at a signal box means a train sitting outside a station with no explanation, and that's how you get complaints to the regulator. Your users' equivalent is a one-star Trustpilot review.
Pattern Two: Degrade the Feature, Not the System
When the Victoria line has signal failures, the buses absorb the load. The network reroutes. Crucially, the rest of the network keeps functioning.
In code terms: circuit breakers and fallbacks, but with intent. Too many implementations treat a fallback as an afterthought — catch the exception, return null, move on. A proper degradation strategy asks what the user actually needs when this piece is missing.
Can you serve cached pricing data with a "last updated 20 minutes ago" stamp? Show the product page without the live stock count? Queue the email instead of dropping it? Each of these is a bus replacement service for your API. None of them are glamorous, and all of them are the difference between an incident and an outage.
Pattern Three: Publish Your Delays
Here's the uncomfortable one. National Rail publishes a public API of its own delays. TfL publishes disruption data that third parties build entire apps on top of. The infrastructure operators treat their failures as data — versioned, queryable, open.
Most commercial teams do the opposite. Status pages get updated hours late. Post-mortems stay internal. Incidents become folklore passed between senior devs in the pub.
You don't need to go full open data, but a couple of habits transfer directly:
- Machine-readable status. If your status page is a wall of HTML, your own monitoring can't consume it. Expose a JSON health endpoint that reflects real dependency state.
- Timestamped honesty. "Investigating" at 09:14, "identified" at 09:31 — the discipline of a timeline forces you to actually understand your own incidents.
- Downstream courtesy. If you're a dependency for someone else, your failures cascade into their dashboards. Give them the same structured honesty you'd want from your providers.
The Bank Holiday Corollary
We've written before about not deploying on bank holidays, and the same logic applies to degradation. Sunday at 23:00, with the reduced timetable running and half your team on annual leave, is exactly when your fallback paths matter most. Test them when the office is quiet, because the rails don't stop running just because it's a Sunday.
The British transport network is nobody's idea of a triumph. But the principle underneath it — tell the truth early, keep the essentials moving, and treat failure as an operational state rather than an embarrassment — is worth more than most architecture diagrams. Your users don't need your system to be perfect. They need it to be honest when it isn't, and to have a plan for the days when the signals fail.
That's not pessimism. That's just good engineering, with a British accent.