Teaching Someone to Debug Is Harder Than Teaching Them to Code
Syntax is teachable in a week. The thing that separates a good debugger from a bad one is a skill nobody quite knows how to transmit.
I have onboarded a fair number of developers now, across three companies, and I keep noticing the same gap.
Teaching someone a language is straightforward. Syntax, idioms, the standard library, the framework. A capable person is productive in weeks and it is mostly a matter of exposure and practice.
Teaching someone to debug is much harder, and I do not think our industry has a good answer for it.
What separates the two
Watch a junior and a senior engineer approach the same unfamiliar bug.
The junior reads the code from the top, looking for something that looks wrong. When nothing does, they add print statements at plausible places, run it, read the output, and add more. It is a search, and the search order is roughly the order things appear in the file.
The senior asks a question first. Usually some version of "what does the failure tell me about where it cannot be?" Then they run one experiment that eliminates a large fraction of the search space.
The difference is not knowledge of the codebase. It is that one is searching and the other is bisecting.
What the skill actually is
I have tried to articulate this for a while and the closest I get is: debugging is the ability to hold a model of the system, notice which part of the model must be wrong, and design a cheap test for it.
Three separable components.
Holding the model. Knowing roughly what should happen, in enough detail to notice a deviation. This is the part that genuinely requires experience with the specific system, and it is the part people assume is the whole thing.
Noticing which assumption is suspect. This is the hard part and it is mostly transferable. Given a symptom, which of the fifty things you believe is most likely false? Every bug is a wrong assumption, and the skill is developing a prior over which of your invisible beliefs tends to be the false one.
Designing the cheap test. Given a hypothesis, what is the fastest experiment that would falsify it? Not confirm it. Falsify it.
Most training focuses on the first, which is the least transferable. The second and third are where the leverage is.
Why it is hard to teach
The reasoning is invisible. When a senior engineer solves something in ten minutes, what the junior sees is ten minutes of typing followed by an answer. The eliminations that happened silently are the whole lesson and they were never spoken.
We narrate the wrong parts. Postmortems and writeups tend to present a clean path from symptom to cause. Nobody writes down the three hypotheses they abandoned, which is precisely the content that teaches method rather than facts.
Feedback is slow and noisy. You find out whether your approach was good hours later, and the outcome is confounded by luck. Sometimes a bad approach gets lucky. That makes the learning signal weak.
Nobody watches anyone debug. We review code constantly and we almost never observe each other's process. It is the highest leverage skill and the one we get the least feedback on.
What has actually worked
Things I have tried that produced visible improvement.
Narrate while debugging, including the dead ends
Screen share and talk continuously. Not "now I will check the logs" but "the error is in the payment path, and p50 is unchanged, so most requests are fine, so it is conditional on something. Let me check whether it correlates with a payment method."
The eliminations are the lesson. Saying them out loud is the only way to transmit them.
This is uncomfortable, because narrating includes narrating being wrong. That is the valuable part. A junior who watches a senior form three wrong hypotheses and recover learns something they cannot get from a writeup.
Ask "what would you check next, and why the why"
When someone brings you a bug, resist solving it. Ask what they would check next and, crucially, what answer they expect.
"I would add a log there" is a search. "I would add a log there because if it prints, the request reached the handler, which rules out routing and the load balancer" is bisection.
The second half is the skill. Asking for it repeatedly makes people supply it unprompted within a few weeks, which is faster than I expected.
Make them predict before running
Before running the experiment: what do you expect to see, and what would each outcome mean?
If both outcomes lead to the same next step, the experiment is worthless and you have just saved five minutes. If they cannot say what they expect, they do not have a hypothesis, they have a hunch.
This one habit changes more than anything else I have tried.
Teach the shapes
Certain symptom shapes carry a lot of information and they are learnable as facts.
- p99 up, p50 flat: a conditional slow path, not general degradation
- CPU flat, latency up: waiting rather than computing, so lock, disk, or network
- Fails in CI, passes locally: environment, ordering, timing, or case sensitivity
- Intermittent and rare: race, resource, or a data dependent branch
- Worse under network throttling: an ordering problem
- Worse under CPU load: a timing window
These are pattern recognition and they can be taught directly. I have seen a list like this measurably speed up a new engineer, because it converts a blank page into a small set of candidate directions.
Aggregate before investigating
The single most common mistake I see, at every level, is examining one instance of an intermittent problem.
A batch job that failed for five months was solved in ninety seconds by counting failures by weekday. Four engineers had examined individual failures.
"When it is intermittent, count before you look" is one sentence and it changes behaviour.
What does not work
Telling people to check their assumptions. True, universally agreed, and operationally useless. Nobody knows what to do with it at 2am. The useful version is a list of specific assumptions that are commonly false.
Debugging exercises with planted bugs. They teach searching, because the bug is known to exist and to be findable, which is not the real situation. Real bugs come with uncertainty about whether there is a bug at all.
Tool training in isolation. Knowing the debugger's keyboard shortcuts is not the skill. I have watched people who know a debugger extremely well flounder because they had no hypothesis to test with it.
The part I am least sure about
I do not know how much of this is teachable versus selected for.
Some people arrive with it. They have an instinct for where to look that seems disproportionate to their experience. Others are strong engineers in every other respect and remain slow at this for years.
My honest current belief is that the components differ. Designing cheap experiments is teachable and improves quickly with the prediction habit. Building an accurate mental model is mostly exposure. And the intuition about which assumption is suspect seems to be the slowest to develop and the most variable between people.
That last one might just be accumulated pattern recognition that looks like intuition from outside, in which case the answer is more reps with narration. I am not confident.
What I am confident about: it is worth explicitly investing in, and almost nobody does. We have code review, pairing, and design docs. We have essentially no institutional practice for transmitting debugging method, and it is the skill that most determines how quickly a team recovers when something goes wrong.
Published on debugly.dev by Rohit Bhadani | Founder of Krova Cloud