If anything, I think debuggers are nice for simple, borderline trivial programs where everything fits on a screen and there's a handful of variables to keep track of. (These tend to be the programs I rarely need a debugger for though, and the debugger isn't necessarily any faster than a bunch of print statements). They're nice for getting stack traces or figuring out the contents of RAM and sometimes that's just what you need, but often that's just working your way backwards towards the real issue, without having a way to rewind time.
rr might change a lot of that, if it's available for your platform..
Put a breakpoint early on startup, once hit put a data breakpoint on the part of the state which messed up, reproduce the bug, and there's very high chance debugger will take you to the code which broke the state.
This will even happen if the code which breaks the state is a memory corruption bug in different thread, in the code written in another language, from a third-party DLL.
> debuggers are nice for simple, borderline trivial programs where everything fits on a screen and there's a handful of variables to keep track of
It's funny I think it's the opposite. When there's only a few variables, one can print/log the complete state pretty often. When the state takes a gigabyte of memory and changes often, similar amount of logging going to produce too many terabytes of logs to be useful. Debugging is interactive, you can inspect the complete state and find the most relevant pieces to watch.
Except when you find the data you're after doesn't exist early at startup, it's allocated on the fly as connections come and go, and you need thousands of connections to come and go before the bug manifests, and the data that eventually gets messed up may first be used thousands of times before it's wrong all of a sudden. IME it's precisely these multi-threaded memory corruption bugs that really resist debuggers. And as is often the case, debugger changes timing so much that the bug doesn't even reproduce.
Even if you find the code that corrupts the memory, it might be totally okay, it just somehow got passed the wrong memory long ago through no fault of its own (or you're looking at a use-after-free).
But when the one in my comment does work, the saved debugging time can be measured in days.
Speaking about debugging tactics, there’re way more than just two. There’re OS-level tools like process monitor on Windows / strace on Linux. There’re specialized tools like RenderDoc or Wireshark. For different types of bugs, these tools can sometimes also save days of work compared to other methods.
That's why I don't really like an absolutist stance (if you rarely use debugger you're dumb / if you always poke around with a debugger you're dumb). I just happen to fall in the "rarely uses debugger" camp myself.
> I’ve done hundreds of interviews like this, and it’s fascinating watching what people do. Do they read the code first? Fire up a debugger? Add print statements and binary search by hand? [..] After hundreds of interviews I still couldn’t tell you which approach is best.
Knowing which part of the state messed up is like 90% of the debugging. Most of the time the part of the state you see messed up is like that because another part of the state is also messed up. Given that neither debuggers nor logging can go back in time to backtrack the state (well, time travel debuggers exist but aren't common or cover all cases), it's usually faster to inspect the code manually to try to find the original bug instead of re-running continuously to backtrack the state.
I’m not sure how usual that is. Sometimes “the code” is too many thousands of lines to inspect. Other times, “the code” is only the machine code but not the source code, inspecting megabytes of disassembly is not fun.
> inspecting megabytes of disassembly is not fun.
Well, of course there you need the debugger and memory watchers. But I think that fits into the "unusual" slot, most people aren't doing that.
I've seen quite a few threads on r/php where individuals introduce a newer, supposedly better, library that can be used instead of `var_dump`, and there's always the inevitable "why not use the debugger?" to which many reply "because it's hard to set up" or "var_dump is better" or something silly to that effect.
You also wouldn't generally be debugging a request from random clients. You'd generally be debugging in your local dev environment.
This is not a judgement, just an observation. I always assumed debuggers were just part of a tool set but it appears (in my experience) many individuals were never taught that it exists.
I also do not claim its a magical tool that can solve all problems. There are plenty of times i do a "print 'i'm here' + var".
Those who can't code, debug. :-)
Joke apart it's a style thing, tracing and thinking gets you a long way, though virtuoso debugger users can be productive too no doubt. It's a bit like GUI vs CLI.
In practice, most software is a stack of abstractions and bugs can be caused by anything at any level of that pile, including libraries. The ability to quickly inspect the state at a given execution step is not a tool that can realistically be dispensed by just thinking hard about the code.
There's another great benefit to a debugger, and that is troubleshooting long-running code or hard to prime iterations. Like for example, debugging a checkout flow can be very cumbersome as you have to prime the state for every test. There are plenty of workarounds if you have to log your way through it, but wouldn't it just be easier to use a tool designed for the job?
I also do a lot of low level code (kernel/bootloader) where debuggers can be available but are often a lot harder to setup. Keep in mind that I also don't like IDEs and my coding setup is mostly vim + ctags + terminal.
I really agree with the quote in TFA, when I write rust code a few judiciously placed dbg!() calls are generally all I need to identify the issue.