Engineering
Debugging Like an Engineer, Not a Fortune Teller

6 timeless debugging principles worth practicing

2/23/20262 views
How great engineers debug code

Debugging often feels emotional when systems are down and pressure is high. But the best engineers treat it like an investigation, not a lottery.

This note is inspired by a LinkedIn post from Alexandre Zajac, then reframed through my own engineering workflow.

Source inspiration: https://www.linkedin.com/posts/alexandre-zajac_i-studied-how-6-legendary-engineers-debug-activity-7431374226223349760-_HDB

1) John Carmack — Isolate first

Carmack-style debugging starts by shrinking the failure scope. Instead of exploring ten hypotheses at once, strip the system down until only the smallest failing case remains.

  • Remove non-essential layers.
  • Disable extra variables one by one.
  • Keep only what reproduces the bug.

When the problem becomes small, the path to a fix usually becomes obvious.

2) Linus Torvalds — Verify assumptions in code

Logs are clues, not ground truth. Reading the source of the failing path reveals what the system actually does, not what we think it does.

A lot of bugs survive because assumptions survive.

  • “This function must return X” → confirm it.
  • “This state is always initialized” → verify it.
  • “This branch should never execute” → prove it.

3) Margaret Hamilton — Design for failure

Defensive engineering means testing what should not happen, not only the happy path.

  • Invalid input formats.
  • Partial network failures.
  • Retries, duplicate requests, and race conditions.

If an edge case is possible in production, it is not “edge” — it is expected reality.

4) Grace Hopper — Reproduce reality

Second-hand bug reports are a starting point, not the finish line. Reproduce the exact environment and sequence that triggers the issue.

  • Same data shape.
  • Same deployment config.
  • Same timing and sequence.

Without reproduction, you risk fixing symptoms instead of causes.

5) Dan Abramov — Write expected vs actual

One of the cleanest debugging prompts is:

“I expected X, but got Y.”

That single sentence forces clarity. Once expectation and reality are explicit, the mismatch becomes actionable.

If I cannot explain the bug in one paragraph, I am usually not ready to patch it.

6) James Gosling — Make systems observable

Great systems help explain their own failures.

  • Structured logs at service boundaries.
  • Correlation IDs across requests.
  • Error messages that include useful context.

Observability turns mystery outages into traceable incidents.

What changed in my own workflow

Recently, I’ve been using a simple sequence whenever production behavior drifts from expectation:

  1. Reproduce the issue with minimal scope.
  2. Write expected vs actual behavior.
  3. Trace boundary inputs/outputs with structured logs.
  4. Patch only after root cause is confirmed.

This flow reduced back-and-forth fixes and made postmortems cleaner.

Closing

None of these approaches start with guessing. They start with understanding.

Method beats talent over time.

If you want to improve your debugging, pick one principle and practice it for 30 days. Track your resolution time and stress level — both usually improve when your process gets sharper.