Reputation: 116401
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?
Upvotes: 11
Views: 6391
Reputation: 6583
This is by no means a technical tip but it often works in my case.
Just stop working hard to find a root cause or fix a bug. Relax for a while: take a walk, eat dinner, or just switch to another task (hopefully much easier) - whatever you like...
...Then think about a problem a bit later, when you're "fresh" again. Trace back all the mental process of debugging that you already went through (theories, experiments, assumptions etc. that you made). Chances are that you will instantly see some key factor that you overlooked before ;).
Programmers (or at least me) tend to gradually narrow down thier perspective of problem and wear off of creativity during a long debugging session. But wide perspective combined with creative ideas are man's most powerful weapon in the battle with bugs!
Upvotes: 1
Reputation: 8386
Another thing I've started doing to all my projects is to add a TraceListener (or derived class) and using it to take key snapshots of my application.
This usually gives me a good idea of where to focus my initial debugging efforts.
Plus, I can it on/off using a config file switch, so I can even get a hint on a production system, without recompiling the code.
Upvotes: 0
Reputation: 1239
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
Upvotes: 9
Reputation: 6921
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)
Upvotes: 2
Reputation: 780
This book is honestly the best I've read about debugging, especially when you are beyond the normal debugging situation. It contains many tricks and is fun to read with all the "true story". If you are working with a big amount of code that you haven't written yourself, especially if it's crappy, this book is a must!
alt text http://ecx.images-amazon.com/images/I/51RQ146x9VL._SS500_.jpg
Upvotes: 2
Reputation: 10482
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.
Upvotes: 1
Reputation: 75804
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.
Upvotes: 0
Reputation: 72808
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.
Upvotes: 1
Reputation: 37103
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
Upvotes: 13
Reputation: 346300
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.
Upvotes: 1
Reputation: 75427
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.
Upvotes: 1
Reputation: 3138
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.
Upvotes: 0
Reputation: 12705
Not directly related to debugging, but to make debugging easier in the future, there are a few things to consider:
Upvotes: 5
Reputation: 7949
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.
Upvotes: 3
Reputation: 4193
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.
Upvotes: 5
Reputation: 2156
One very best practice is not diving into debugger immediately but look at the code and think hard for some time.
Upvotes: 11