CodeCrafting All articles
Build & Delivery

Designing for the 2am Debugger: What Your Change Looks Like When You're Asleep

CodeCrafting
Designing for the 2am Debugger: What Your Change Looks Like When You're Asleep

Photo: New Brunswick / Nouveau-Brunswick, Public domain, via Wikimedia Commons

Picture it. It's 01:47 on a wet Tuesday and the person on call has been woken by a pager for the second time this week. They didn't write the code that's misbehaving. The author is asleep, possibly in a different timezone, and definitely not answering Slack. Everything they have to work with is what the change left behind: log lines, names, error messages, and a runbook someone wrote in a hurry before a bank holiday.

That scenario is the real acceptance test for a production change, and it's worth running in your head before you merge. Not does it work — you've got CI for that — but could a tired stranger work out why it's broken from the wreckage?

The test is a habit, not a gate

This isn't a call for a heavyweight checklist or a new column in Jira. It's a two-minute mental exercise: imagine the least-context-rich engineer on your rota, at the worst hour, with the least patience. Then read your own diff as if you were them.

Craft, in this sense, isn't about elegance for its own sake. It's about consideration for the next person. The next person might be a colleague, a contractor, or you in six months when you've forgotten everything except roughly where the file lives.

Log lines are documentation with a deadline

Most logs are written for the happy path, where nobody reads them. The ones that matter are written for the bad day.

A line that says Processing… earns nothing. A line that says invoice_reconcile_failed invoice_id=8842 attempt=3 reason=timeout upstream=billing-api lets the on-call engineer search, correlate and move on. Same number of keystrokes, wildly different value.

A few ground rules that pay off repeatedly:

Names carry the night shift

Half of debugging is vocabulary. If the function is called handle_data, the on-call engineer has to open it and read it to learn anything. If it's called reconcileInvoiceLines, they already know what it's for and roughly what breaks when it fails.

The same goes for variables with units. timeout is a riddle. timeout_ms is an answer. Somewhere in your organisation there is a bug caused by someone assuming seconds. You can prevent the next one.

Error messages deserve the same treatment. Invalid input tells nobody anything. quantity must be a positive integer, got -3 tells them exactly where to look, and often tells the user what to do differently.

Design the failure, not just the success

The 2am debugger benefits far more from a well-considered failure mode than from a beautifully factored happy path.

Ask yourself, before merging:

None of this needs a framework. It needs ten minutes of thinking about the bad day while it's still someone else's problem.

Runbooks that survive contact with reality

A runbook nobody can find is decoration. Keep it next to the code, or link it from the alert — not in a wiki page three clicks from anywhere, last edited in 2023.

What actually helps:

  1. One screen. If it's longer, it's a document, not a runbook.
  2. The first five minutes. How do you confirm this is the problem? Which dashboard, which query?
  3. The escape hatch. How do you roll back, and what breaks if you do?
  4. The escalation. Who to wake, and at what point it's reasonable to wake them.
  5. A date and a name. Undated runbooks are folklore.

Release habits for a team of six

None of the above survives a team that ships in heroic Friday-afternoon batches. Small, boring habits do more than any process document:

The quiet payoff

The 2am test doesn't make incidents disappear. It shortens them. It turns a two-hour scramble involving three people and a guess into a fifteen-minute look at a log line that says exactly what went wrong.

That's the whole trick: write the code as though the person debugging it is tired, unfamiliar and slightly annoyed — because one day, that person will be you.

All Articles

Related Articles

Same Bytes, Every Time: Reproducible Builds as Risk Management, Not Ritual

Same Bytes, Every Time: Reproducible Builds as Risk Management, Not Ritual

Pull Requests Without the Mumbling: How to Review Code Honestly and Kindly

Pull Requests Without the Mumbling: How to Review Code Honestly and Kindly

The Repair Café Mindset: Keeping Legacy Systems Alive Without the Grand Rewrite

The Repair Café Mindset: Keeping Legacy Systems Alive Without the Grand Rewrite