I Don't Understand This (Yet)
iamjonas.me
iamjonas.me
I feel like this is not a helpful take on debugging for most of us. I'm certainly not as good at this as Ken Thompson, and very seldom is the problem space simple enough that I can hold a complete mental model of it in my head. Instead I reach for the debugger to collect more data on what's going on. And I can usually find the issue by looking a lot faster than I can correctly theorize about it.
In Debugging by Davig J. Agans, his third rule is "Quit thinking and look". And I tend to agree. In the majority of cases when I'm debugging a problem the solution only reveals itself when I see that missing piece of information.
EDIT: As others have rightly pointed out, if I wrote the code I've already thought about it and have a mental model of what I wrote. And yes, I do think about what could be causing the problem. I guess it's those cases where I think it should be working in a certain way, but it isn't, where I find it most valuable to stop thinking and look. And usually in those cases I either have an incorrect or incomplete model, or I wrote something that didn't match what I was thinking.
This is why it is relatively easy to work on a project you were in on from the beginning.
and why it is always a struggle to come into a project with an existing codebase.
I've spent many years working on large existing codebases and it gets in the way of liking your job.
Yes, and unless there was a simple typo, the problem is the model in your head. Most bugs come from unchallenged assumptions.
For some reason, not being on the keyboard or operating tools seems to free up a lot of mental bandwidth.
Nothing gets done without someone being hands-on though so arguably yes, that role is more important. If there's just 1 person they usually have to stop and think really hard periodically and keep very good notes to avoid getting lost in the weeds.
Sitting and thinking on the other hand, is best for dealing with errors in your own thinking. Ideally, we should have a well-thought-out argument for why something will work, so when it doesn't, our argument needs to be refined.
For the first the remote server could say there is no Authorization header where tracing confirms it was there when sent by the client but not by the proxy.
For the second it would be really nice to see more detailed logging on the server side about why a particular peer certificate was rejected. My biggest gripe with current OpenSSL and Java TLS implementations is this lack of detailed reporting.
Regardless of the details this is one of those situations I wasn't able to solve by just thinking about it. If I had a 'debugger' that could step through these API requests it would have been much easier to figure this one out. I don't know enough about OpenTelemetry to say if it would have helped or not.
Even if thinking has not solved the problem, it may help you find where to look next.
One tip I have is that even if you wrote the code and think you know how it works, stepping through it in your mind might lead you to see where you are making a questionable assumption.
You may think that you can do that just as well in the debugger, and you may be right, but there are two ways of using the debugger: one is to hit 'step' and see what happens; the other is to figure out what you expect will happen, and then check if your expectation was correct. There have been many times when I have stepped up to the point where the bug is about to happen, and then realized what is wrong before taking that final step.
[1] I myself don't use a debugger much; I'm frequently working on something distributed where a debugger is laughably useless.
You already have a more narrow sense of the problem space, else you wouldn't know where to look with the debugger either...
BUT. Where I think the OP is right is what you do with the debugger. I agree with OP that you shouldn't use the debugger just for generalized "seeing what is going on" or jump too quickly into "finding the problem".
You should be using it to prove or disprove a hypothesis. Initially, hypotheses about your mental model, not about the problem itself.
But you can and often need to use the debugger in order to build the mental model.
The next part of quote from OP is:
> What Ken was doing was constructing a mental model of the program. When something broke it was an error in that model. He'd think of how that error might happen or where the code might not satisfy the model.
You absolutely can and I'd go so far as to say even should use the debugger as an aid to building the mental model. If you're not Ken Thompson, and depending on how familiar you are with the code, and the nature of the platform and codebase, it isn't necessarily useful to just be totally inside your head trying to "build the mental model" and think of what might be breaking it.
So it's not really about how quickly you pull out the debugger. But it is absolutely good advice not to immediately start debugging ("find the problem") with it, and not to just use the debugger aimlessly, but to start with a separate "mental model phase".
I see why the OP wants to tell you not to use the debugger in this phase, to help you understand it is in fact a separate phase, and because the debugger can lead you to miss the forest for the leaf. But you can and probably often should use the debugger there too, I agree. But you use it to build your mental model -- if you aren't sure you have a mental model, make some guesses (about how the code works, NOT about "what's wrong"), then use the debugger to confirm or deny them. To figure out "how does this code work, big picture" before trying to use it to figure out "why is it broken".
IF you are pretty familiar with the particular platform and codebase, AND pretty experienced with doing this kind of work, you might not find the debugger helpful for that first phase, like Ken Thomson. But i'd argue it's also fine to use the debugger there, it's a question of what you are using it to do.
My debugging goes like this:
1) I need to have a model in my head of what I think is going on even if simple.
2) I make a change X with the idea that result Y should happen. VERIFYING THIS HYPOTHESIS IS VITALLY IMPORTANT. Your change should create cause and effect.
3) I test that result Y actually happened--generally this is where I'm using the debugger.
4a) If result Y happened and result Y means my program is fixed, congratulations, you are done.
4b) If result Y happened but my program is not yet fixed, go back to make another hypothesis and go back to step 2.
4c) If result Y did not happen, undo change X, update your mental model and go back to step 1. This is where the "think hard" part mostly comes in.
The toughest bugs are the ones that require you to update your mental model the most.
Often it's the reverse: printfs, data file dumping, etc. are impossible, but the debugger is always there. If you find yourself chasing a bug into glibc or Rust stdlib, printf debugging won't be sufficient. Using a debugger is an underrated skill.
I'd add also that the focused mode often gets you stuck even more under stress. Both approaches are complimentary. This kind of problem solving needs thinking pace, just as if mind were a CPU with a program being weaved in real time, morphing constantly, seeking patterns, eliminating choices.
- Hey, Jim, are you sleeping at your desk? - No, Mr. Stone, my mind is thinking! Just be patient and please don't interrupt...
On a serious note, under the stress or not, it's important to recognize when one's own mind got stuck. Getting other people involved (as listeners or active participants) is often the only way to get through without exhausting oneself. I wish this was more encouraged in teams, instead of my task must do kind of approach.
When you are done you would have come up with at least one new thing to try.
One more approach that worked several times for me is to start writing a Stackoverflow question, carefully formulating the problem for the reader who does not have your context. Often I saw the answer before you finish writing, and never posted the question.
It really helps to have these things written down somewhere as you can easily refer back to them as you revert back up the depth first search stack in your head. I guess some people can do this entirely in their head but I can't especially with all the interruptions one has.
One of our guys actually had an actual rubber duck sent to them by their employer. This was for a remote only position like 10 years ago by now.
I had one fake AHA moment and but then it was gone again. Not sure what that says about me.
Edit and spoiler warning: Looked up the solution and I think the picture is misleading. It implies that pyramid staying on same height.