As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
If this question can be reworded to fit the rules in the help center, please edit the question.

Debugging other's code is a huge time waster, productivity killer, but that is how it is. The only time when it really makes sense to fix other's bugs is when they have left. What I HATE HATE HATE is going through some objectively crappy code by a senior coder, then having to ask a question in order to make timely progress, and getting a lecture on improving my skills at learning the existing code base. Unlike studying the mother nature, solving human-caused screw-ups is hardly fun. At least I get my answer. The reverse situation will not happen, because I am just better and leave fewer bugs.
–
JobNov 28 '10 at 0:56

1

@Job: ... okay? Did you mean to leave this comment on the post, perhaps? :)
–
Anna Lear♦Nov 28 '10 at 6:10

This! It's silly to blindly trust any small bit of your code if you're debugging a weird issue and the code seems fine.
–
DanFeb 13 '13 at 13:21

Go depth first in your code and test it from smallest module moving up gradually.In this way, you are not under too much stress trying to figure out where the problem exactly might be.

It also means that it affects less code at a time since you are moving incrementally..as at times I have had issues where I fixed something and that lead to breaking lots of other stuff. I give credit to my boss for this as he taught me this when I messed around.

Divide and conquer is a good approach. Try to identify some visible input (user input/network event ...) and output (log, output to user, outbound network message ...) between which the issue exists. Try putting prints at sizable chunks or significant points between them and try to narrow down where the bug is in the code.

Divide and conquer can also work very well in case of regressions over version controlled code. Find two builds - one where it works as expected, other with the regression. Narrow the gap down till you are left with a bunch of checkins as potential suspects.

To verify what you actually know to be true about the functioning of the app versus what you assume to be true.

Most IDEs make it easy to extract methods and to generate xUnit testing stubs. Make use of that.

Why not sprinkle debugs? Because after you are done, you will likely have to undo much of that work and delete a fair amount of those debugs. When you write tests, your debugging will aid in the prevention and detection of future bugs.

As others have said - do not assume anything. This is especially true if its code you've written. When debugging others code you are more likely to slow down because the code is new to you or you don't trust the coder. When debugging your own code its too easy to assume you wrote it correctly, slow down!

For the actual process of debugging:

Write unit tests if they don't already exists.

Add appropriate logging if doesn't already exist.

Then use the debugging.

Adding the unit tests and logging first more efficient that using the debugger first up. You also get the added advantage of having the unit tests to help not introducing future bugs and the logging will help debugging sessions in the future.

Before stepping over a small chunk of code, see if you can accurately determine the outcome. This does tend to fly in the face of don't assume anything (which I up voted BTW) but as you gain experience, it can help narrow down where to look.

This may sound trivial, but learn the nuances of your debugger and learn the hot-keys. Sometimes debuggers can be slow enough that your mind wonders when your stepping through. If you can keep up with the machine and aren't mousing around, that can help.

If you can modify code while debugging:

consider asserting pre AND post conditions. Sometimes you can then step over, instead of into code.

for if statements with complicated expressions, consider something (some may frown at this but it works for me)

For the cases you can't debug everything, for whatever reason, learn to "rubber-duck" with a co-worker. Sometimes the act of explaining sheds light. (ok, maybe this isn't exactly in the questions theme, but I think it's close enough to warrant mention)

The naming of subconditions needs a step more, namely the refactoring of the names when you find out what the condition is for. It might turn out to be if (tooCloseToHydrant || overTheBrink) { when you learn more later.
–
user1249Nov 28 '10 at 10:36

Two things, based on spending most of the last 22 years maintaining code other people wrote.

Understand the kinds of bugs you tend to write.

For instance, I'm a very meticulous coder, so once my code compiles, it's usually free of trivial bugs. So my bugs tend to be weird complicated things like thread deadlocks. On the flip side, I have friend who mostly writes trivial bugs - semicolons at the end of C++ for loops, so the next line only gets executed once, that kind of thing.

Don't assume other people write the same kinds of bugs you do.

I don't know how many times I've wasted time pulling out the big debugging guns, assuming a bug was my kind of really subtle weird thing, only to have my friend look over my shoulder and go, "Did you notice that extra semicolon?" After years of that, I first go for the trivial, low-hanging fruit when looking at other peoples' code.

Do you reformat code to see if anything moves around?
–
user1249Nov 28 '10 at 10:51

@Thorbjørn: If I've taken ownership of the code, I sometimes do it to improve readability, but not to find typos. Interesting idea!
–
Bob MurphyNov 28 '10 at 20:25

you do not have to commit it, just see what happens. I can strongly recommend enforcing a polity that requires code to be reformatted - preferably automatically - when checked in.
–
user1249Nov 28 '10 at 20:47

@Thorbjørn: I'd love to do that. What do you recommend as a code "prettifier"? I mostly work on Linux and Mac.
–
Bob MurphyNov 28 '10 at 22:01

I use Eclipse available both places, and the Java editor has a socalled Save action where you can specify what should happen each time the file is saved. Here one of the options is formatting the source. We are a small team so I have not investigated more in it. More experienced teams allow for pre-commit hooks in the source control systems, allowing a source commit to be rejected if it is incorrectly formatted. Very efficient.
–
user1249Nov 28 '10 at 22:28

Know your tools. For example, Visual Studio's debugger has an awesome feature called TracePoints that are like breakpoints but instead of stopping your code instead inserts a trace statement into the debug output.

Reading books or taking a class on how to use your debugger is highly recommended. I took a couple of classes and read a few books by John Robbins that made a big difference in my effectiveness as a debugger.

If you've narrowed it down to a small region, but can't still can't spot the error, try the 'view code + assembly' option of your debugger. Knowing enough ASM to say "there should be a branch here" or "why is it only copying the low word?" will often pinpoint the coding error.

The slides for the book are available online, but I find the book itself is easier to read.

The book will help get you started and make you think more scientifically about debugging, but it's no substitute for practice. You may need to be writing and debugging for 10 years before you see an order of magnitude improvement in your performance. I still remember having my jaw drop at Sun seeing senior developers, who have been programming for Unix for 30 years, find obscure multithreading or parallel bugs in minutes. Experience matters!