I like this quote from Mr. Robot. Most of the time a bug is not an error in logic, but a misunderstanding in how some component of the system works or an unexpected outcome of the emergent behavior of basic rules. Always check your assumptions.
- fatigue bugs
- inattention bugs
- typo bugs
- unknown unknown bugs
- bad merge bugs
- upgrade bugs
- multiple teams or devs screwing up together bugs
I mean, you can always stretch the meaning of "assumption" to match any of those. But to me realistically "assumption" is more about when you conscientiously suppose things.
After all "unexpected outcome of the emergent behavior of basic rules" could be pretty much be applied to anything. And when your definition can be applied to anything, it's not that much of a definition.
You can also view assembly and registers.
This and learning how to set breakpoints properly in GDB and perhaps analyzing a binary with IDA Pro plus searching via Google a lot is what really helped me.
I once got to listen to a brief lecture by a genuine 10x programmer. The title was something like, "Why I'm 10x better programmer than you." and believe me, we were all eager to hear what he said because we knew he was freakishly better than us. (I mention that because some people, reading that title, might get the wrong idea. Dude is cool, title was tongue-in-cheek, it's all good.)
Anyhow, the main take away was this:
"Always have 100% confidence that you know exactly what the code is doing."
If anything ever happens to indicate to you this is not the case (that you know exactly what the code is doing) stop immediately and do whatever is necessary to re-establish that condition (of knowing exactly what the code is doing.)
And let me be clear, he meant down to the machine code.
Why is that a "bonus". If I manage to create a failing test, I'll definitely want that permanently in the test suite.
Debuggers have a mixed reputation on HN ("I never use a debugger; logging statements are way better") but IME too many developers, especially ones fresh out of school, literally have no idea how to set a breakpoint and step in/out.
For those who do know how to set a breakpoint, that's typically all they know (and so they assume that debuggers aren't very useful); they don't know how to drop ("restart") stack frames, run arbitrary code in the debugged process, set conditional breakpoints, ignore ("blackbox") files, debug remote processes, edit the in-process code without restarting, etc. etc. etc.
Every developer working on code mostly written by other people should learn how to use their debugger's tools thoroughly.
While I agree SQL stored procedures should be slim, I've had situations where I had to write very complex ones even though I argued against it.
In this situation, having an input the system works for, and having an input the system fails for is useful. (You can usually try to experiment to narrow down to _why_ the failing case fails).
I've seen coders spend hours debugging problems, stepping through line-by-line in their IDE, and not finding the problem. Then when I suggest they stop, step through the creation of the bug, and just think about what algorithms and data changes are occurring at each step, they often have an epiphany and realize where the problem must lie.
By all means, use the tools that are at our disposal, but the most important part of debugging is simply to think.
All the prior exploration probably often lays the foundation for that epiphany, though.
One “unpopular opinion” I have is that once you’ve written enough code, ignore this advice and assume that it’s the library’s fault very quickly into your debugging session. Some small fraction of the time you’re actually going to be right and you’ll have saved yourself some work, and the times you’re wrong I argue that you’re actually not any worse off. For example, if you have a function returning an error, just assume that the framework is making a mistake somewhere: I tend to find myself that I’m a lot more thorough and open-minded at reviewing other people’s code than my own, so I’ll look a lot more for the reason why it’s behaving in an unexpected way. Often this gives me insight in to the internals of something new for free along with the solution (oh, the error is being created at this check inside an internal function because I passed in NULL and I shouldn’t have).