No Debugger?
I rarely use a debugger. When I do, I generally shouldn’t.
I used to pride myself on not even knowing how the debugger worked, but a few months back I accidentally learned. So now I know … and I also know that when I am tempted to use it, I’m almost certainly in trouble.
When I’m working at my best, I am no more than a few minutes away from being able to commit and push my code. There may be one new capability that isn’t working, but all my tests but run will be working, and when the one failing test works, I can push the code. Mind you, I don’t work on anything that is mission critical, even in my own living room, but even so, when I’m doing well, I am just minutes away from high confidence that everything is working.
I’ve said many times here and elsewhere that if I go more than about 20 minutes without being able to commit, I’m in trouble and would be wise to roll back to the last green bar and begin again, with something smaller. I am not always wise. I have gone over an hour trying to find a problem. I have ended a session with tests still red and no idea why. I am not always as wise as I might be.
Wisdom aside, it happens quite often that I write a test, write some code to make it work, and it does not work, or, occasionally, some other test breaks. Quite often the reason is obvious: the big advantage to very small steps is that if you’ve only typed a couple of statements, it’s usually pretty easy to spot the problem.
But sometimes, well, it isn’t obvious. In days of yore, my next move would be to set a breakpoint. In days of—what is the opposite of “days of yore”?—in more recent days, my next move is generally to print a value at some critical point, to see what is going on. Often that tells me what I need to know. Sometimes I need another print, earlier or later.
Now of course I could just set a breakpoint at the interesting point and check the value. But that way leads down a path I do not want to follow. If the value is right, but the test isn’t running, I want to step along or set another breakpoint to see what happens. If it’s wrong, I want to set another breakpoint earlier.
And all too often, very soon I’m stepping along watching my program run at one statement every five seconds, and ten minutes, twenty, go by before I find the problem, because I’m no longer really thinking, I’m just stepping and trying to notice something going wrong.
It’s not productive compared to a couple of prints judiciously placed to find the problem, and when they don’t it’s a good sign that I should roll back and try again. In my experience, that is generally faster than debugging once debugging turns to stepping.
So my practice is to forget that I know how to set a breakpoint, and just not to go into that swamp at all.
YMMV, of course. I try different things to see how they affect my work. I’d recommend that practice to anyone. As to whether someone else will benefit from working as I do in one or another specific way, I don’t really know. If you’re interested, you can fool around and find out. In a good way.
See you later!