Debugging Is the Most Underrated Skill

· 5 min read
debugging skills learning

Nobody Puts It on the Job Spec

Job adverts want React, Kubernetes, five years of TypeScript and a working knowledge of six databases. I have never once seen one ask whether you can work out why something broke.

Which is strange, because that is most of the job.

We hire people for their ability to write code, then employ them to spend their afternoons finding out why the code they wrote last month does something nobody asked for.

It’s Method, Not Brains

I’ve watched genuinely brilliant developers lose most of a day to a bug that somebody else would have cornered in ten minutes. Not because one of them was cleverer. Because one had a process and the other had a feeling.

The feeling approach goes like this. Change something. Refresh. Still broken. Change something else. Refresh. Still broken. Add a log line. Remove the log line. Blame the cache. Restart everything. Two hours later you’ve altered nine files, you can’t remember which changes were experiments and which were fixes, and you have learned precisely nothing.

Sound familiar? It should. Everyone does it, me very much included, usually late in the day when I’ve decided the bug is beneath me.

The process approach is considerably duller and much, much faster.

Confused woman surrounded by floating maths equations

Reproduce It Before You Fix It

You cannot fix what you cannot see. If the bug only shows up sometimes, your first job isn’t fixing it, it’s making it happen on demand.

This always feels like a detour and it never is. A reliable reproduction turns debugging from archaeology into an experiment: change one thing, run it, learn something. Without one, every fix is a guess you can’t check, and “I think it’s gone away now” is not a state anybody should be shipping in.

Better still, building the reproduction often finds the bug on its own. You keep narrowing the conditions until the thing that triggers it is standing out in the open, looking slightly embarrassed.

Actually Read the Error

The whole error. The message, the stack trace, the line numbers, the paragraph underneath that you normally scroll straight past.

Most answers are in there. We’ve trained ourselves not to look, because error output is long and ugly and frequently written by someone who did not have our happiness in mind, but the information is usually sitting near the top. Wrong type. Null where an object should be. A file path pointing somewhere your file has never lived.

If you catch yourself theorising about a bug while an unread stack trace waits patiently in the terminal behind you, stop theorising and go and read it.

Halve It, Then Halve It Again

Binary search is the entire trick, and it works on rather more than sorted arrays.

Does it break with an empty request body? Does it break before the middleware or after? Does it break on the previous commit? Every question you can actually answer should cut the space of possible causes roughly in half, and a handful of good halvings takes you from a whole system down to one function.

The mistake is asking questions that eliminate nothing. “Maybe, it’s a race condition” isn’t a hypothesis, it’s a mood. Ask things you can test.

Simplifying counts too. Strip the reproduction back until the bug has nothing left to hide behind. The fixtures, the middleware, the retry wrapper, the queue: remove them one at a time and see which removal makes the problem vanish.

Distrust the Bit You “Know” Works

“That part definitely works” is where the hours go.

The config is loaded. The parsing is fine. The deploy definitely went out. The database actually has the row in it. Every one of those has been wrong for me more times than I’d care to write down. Verify the boring foundations before you go spelunking through the clever code, because the clever code is usually innocent and the boring bit is usually lying.

Make the Invisible Visible

Software fails in the gaps you can’t see, so put some light in the gaps. Logging, tracing, a breakpoint and a proper look at the actual values rather than the ones you assumed were there.

And learn your tools. Really learn them. A debugger you can drive without googling the keybindings, a profiler you understand, a tracer whose docs you have genuinely read. Most of us muddle through on print statements and vibes, which works right up until the problem lives somewhere a print statement can’t reach.

A reliable reproduction turns debugging from archaeology into an experiment.

The Argument Against, and Where I Might Be Wrong

Some of this may be less teachable than I’m making out. Plenty of good debuggers seem to run on pattern recognition built up over years, an instinct for where the rot usually sets in, and instinct is hard to hand over in a training session.

There’s also a decent chance the machines take a chunk of this. Describe the bug, get the fix. If that keeps improving, why grind at the skill at all?

Because you still have to know whether the answer is right, is my honest reply. Though I’d concede I might be defending my own patch here. It’s very easy to decide that the thing you happen to be good at is the thing that matters most. And for early prototypes or throwaway scripts, careful debugging genuinely matters less than the speed of just trying again.

Practising It On Purpose

  1. After you fix something, ask how you could have found it faster, and write the answer down
  2. Learn one tool properly. A real debugger, a profiler, whatever fits your stack
  3. Pair with someone good at it and watch their process, not their fix
  4. Volunteer for the mystery bugs nobody else wants. That is where the practice is
  5. Keep a note of the bugs that fooled you. The patterns repeat, and so do you
  6. When you’re stuck, write down what you know for certain. It is always less than you thought

Nobody will thank you for being the person who can find anything. They will just quietly come to you first, forever.

Thumbs up

Until next time, happy coding!

Available for rescue and re-platforming work

I take over platforms that already exist and are in trouble. Node, TypeScript, React and Laravel, mostly in regulated or high-traffic environments. If something needs rescuing, re-platforming or finishing, my full history is on the CV.

Related Posts

Comments