I’ve found two things helpful when debugging. The first is keep the scientific method in mind—form a hypothesis, test, repeat as necessary. The second is this quote from Sherlock Holmes: “When you have eliminated the impossible, whatever remains, however improbable, must be the truth.”
Also: Always start under the assumption that the bug is in your code. This was super helpful when I was just starting out with programming. I can’t count the number of times that I yelled “there’s a bug in the CPU!” when writing assembly code at uni, which is of course preposterous (well, not really, but the chances that a greenhorn runs into such bugs in simple code is vanishingly small).
In cases where I spent more than a few days debugging, the cause was always an implicit assumption I made (e.g. ‘this piece of code is so simple that the bug is probably not here’ – but weird things can happen if you use a library you’re not completely familar with, or overloaded operators, or languages that concatenate strings when you forget a comma between them…). So at some point, you need to start realizing the implicit assumptions you’ve made.
Another useful approach: always validate your assumptions. The number of times things like:
I’ve helped a ton of people having problems debugging something and in about 2 minutes sometimes managed to debug their problem by just asking if they’ve validated the basics first.