tags:

views:

602

answers:

14

I've been doing quite a bit of debugging of managed applications lately using both Visual Studio and WinDbg, and as such I'm often ask to assist colleagues in debugging situations. On several occasions I have found people aho just insert break points here and there and hope for the best. In my experience that is rarely a useful technique.

My approach goes something like this.

  • Reproduce the problem. Ideally reduce the input as much as possible.

  • Examine what goes wrong and list theories for where the bug may be.

  • Examine one theory at a time by debugging that specific area of the code.

Repeat steps as necessary.

For complex debugging problems I often work with a colleague. For WinDbg this is especially useful.

Any other useful tips or best practices for debugging?

+5  A: 

One very best practice is not diving into debugger immediately but look at the code and think hard for some time.

AnSGri
Good point - and I completely agree. I'm trying to pick up good points on how to prevent people from going into breakpoint / single step through every line of code mode.
Brian Rasmussen
+4  A: 

As another poster says, with some hard thinking, it's often possible to just see the logic error if you understand what's going on.

But often we think we do, and we don't, or we're simply required to fix something that we don't understand too well, so it's back to first principles.

Reproducing the problem is certainly a vital first step. If you can't do this, then you stand no chance of finding the problem, except by accident.

The next step is to establish beyond doubt the path through the code that actually executes when the bug hits. In a WinForms application that might have many events, and more than one thread, this can be anything but a trivial exercise.

Until you know exactly where the code is going, all the theories in the world about where the bug may be are worthless. And if the code is complex, discovering that code does not stop on a breakpoint can be as informative as having it stop.

So in my experience, using breakpoints early and often can be an essential tool for discovering a how code's working.

I often find that when a problem seems particularly intractable, it's because I've made a fatal assumption about what's going on, and not actually verified it.

So my 'best practice' is not to move on until I'm sure I understand, and not guess.

ChrisA
+3  A: 

The barriers to entry for the debugger in VS.NET with a language like C# or VB.NET is just so ridiculously low that it is often easier to insert a breakpoint or two where you know the problem is and just step through.

Sometimes I find myself using Edit & Continue to write code. It's great. You can see results immediately. Often it's most useful when there's some algorithm or relatively difficult to understand loop.

NathanE
+7  A: 

If there was one tip I could give to everyone about debugging it would be to break it again.

That is, when you think you've found the fix and the system seems to work. Back the fix out and see if the system breaks again.

Sometimes you can get lost in the sequence of what you've tried as potential solutions and you finish up in a totally different area of the system while you're debugging the problem. Then you forget what you've changed back in the original area where you were working.

Backing the fix out and then reproducing the problem ensures that the candidate fix isn't relying on something else that you've changed in another part of the system. That your patch for the fix is a correct standalone solution.

HTH.

cheers,

Rob

Rob Wells
+2  A: 

Not directly related to debugging, but to make debugging easier in the future, there are a few things to consider:

  • Implementing unit testing, preferably in the form of TDD, forces you to stay on task and develop only with the goal of passing tests. It is harder to "wander" when you are coding to a test, instead of to a task.
  • Get in the practice of regularly refactoring your code. Small, on-point methods are easier to debug than monolithic "jack of all trades" methods.
  • Utilize your team members. Often adding an extra set of eyes can help flush something out. Chances are, if you do not find something in a relatively quick manner, you are going to continue to overlook it for a while.
  • You can always rollback code in your version control system to try and isolate what version of a file caused the introduction of the bug. Once you do that, you can diff between the last good and first bad and just focus on the changes between the two.
joseph.ferris
A: 

I just replayed in another post, the question was C debugging but as i stated in my replay i think that debugging techniques are language independent.

Ilya
A: 

Like Conceptual Blockbusting suggests, I like to try different ways whenever I get stuck. "printf debugging", thinking about the behavior, binary search on code, binary search on version-control commits, writing a unit test to clarify, scratch refactoring, and also firing the debugger.

orip
A: 

IMO too much preparation is a waste of time. If you know the codebase reasonably well, you can usually right aways think of a few key places where the problem manifests. Put break points there and see if you're right. Whenever you see better key points, move your breakpoints to get closer to the problem.

When you're chasing bad data such as a null pointer, it depends on where it comes from: if it's passed as an argument, look at the call stack to find where it comes from. If it's part of some data structure or object (the easier case), put a breakpoint there to see when and how it is modified.

Conitional breakpoints can be a great help, otherwise you can simulate them by adding if statements enclosing no-ops. If you have a breakpoint in a hot spot that gets hit too often before you get to the problem, deactivate it and put another one in a place you know will be hit shortly before the problem manifests, then activte the one in the hot spot.

Michael Borgwardt
Well, we're quickly approaching a million lines of code, so nobody knows the codebase reasonably well in our case.
Brian Rasmussen
Brian - if nobody in your organisation can narrow a bug down to a few files in most cases, then you have much bigger issues than just the bug. Nobody "trusts" the code and you're racking up technical debt.
MadKeithV
+1  A: 

A good practice is to make sure you're not fixing a symptom, but the cause.

Often, one might see an odd value while debugging and fix it there, without checking what caused the value to get there in the first place. This is, of course, a very bad idea.

BTW, this is why Linus objected adding built-in support for kernel debugging.

abyx
identifying when you're looking at a symptom or a cause is the trick though
annakata
A: 

One thing I like to hammer home is that where you have one instance working and one not (say production and dev) it's about the differences and you need to clearly identify what those could be and deal with them one at a time. Environmental problems can be the hardest to trace and you'll go insane if you don't work systematically.

Incidentally this is one of the reasons I habitually run my VS webapp projects through IIS not cassini anymore.

annakata
A: 

I'll paraphrase my answer on a similar thread (which is essentially the last bullet point in joseph.ferris's answer to this thread ):

Using your version control system, isolate the file revision where the bug was introduced, using binary search tree approach.

Diff that revision of the source file against the previous revision. The diff may make the reason for the bug apparent.

JeffH
+1  A: 
MissT
Yeah- I've read that book. Taught me a few tricks.
RichardOD
+2  A: 

I'm not sure where I read about "Rubber Duck Debugging", but I think its great. The basic idea is to set a rubber duck on your desk and explain the code to it. The idea is that as you explain the code to the duck, you'll eventually find yourself saying "Now, this happens", and you'll notice that 'this' is not what you intend to be happening.

Lacking a duck, I find I just walk through the code and explain it to myself. It works, but I still think I might bring in a duck.

[EDIT] I found where I read about the rubber duck Rubber Duck Debugging

Jeff Barger
A: 

Something that helps, especially when you're new to debugging, is to keep some kind of debugging journal, with solutions to problems you've solved in the past. Most bugs follow relatively common patterns (for instance, apparently random problems in non-threaded applications are usually due to undefined variables, or similar use of uninitialized memory) and by keeping track of those patterns, you'll get much better at nailing in on future problems.

After a while, you just develop the necessary intuition (and then your journal becomes a very fun memory of all the nasty enemies you've conquered)

Kena