I know a lot of times I mention things like Silverlight, AJAX, Unit Testing or some other new cool technology. I talk about upcoming releases of SQL Server or how we may want to evaluate C# as an alternative to VB.NET development for the future and I understand that it can be hard to really care about those things. We all have work to do. We have upcoming releases we're working our butts off to get out the door so it seems like a waste of time to talk about things we don't have the time to implement or research.
With that in mind, I took the time to step back and think about something we could all use every day to help increase our efficiency and productivity. Something that would be beneficial for all of us as developers and be immediately useful. It took me a bit to come up with something, but when I did, it was a pretty obvious area to focus on and it was staring right at me.
I had been trying to recreate yet another crazy error that our loco tester had found and I was kind of running through some different ideas to do for a team presentation for the group in my mind as I was tracking it down. I was getting frustrated because I could make the error happen, but it was only occurring on about the 65th record I was iterating through in a loop. That's when it hit me, debugging was something we all could use some help on. It's something that we all have to do just about every day here on the job and something that even just learning one trick on might help you fix that one issue just that much faster.
That's what I'm going to talk about. This will be a mini-refresher on debugging and I'll mention some of the options and features that are built right into Visual Studio to help you with debugging. Some that I never knew about myself until I start doing the research for this talk.
The Debugging Lifecycle
First let's look at the logical steps of debugging. These are good to think about when going over your issues just to prepare yourself mentally to think through what needs to be done. All the steps aren't always necessary, but most we do at least sub-consciously when working through hunting down that elusive bug. I think learning to do each of these steps efficiently and logically is what makes the difference between being an effective debugger and an inefficient one.
1) Identify exactly what is wrong. This is often done for us in the reported issues, but it's important to take the time to read over the issue and make sure that something coherent has been reported. Don't be afraid to turn it back over to testing if it's not clear just what exactly is wrong. It can be a waste if you spend valuable development time just kind of guessing what they meant. Get it clarified and be absolutely sure you understand what is being reported before you even begin debugging and working on the issue.
2) Recreate the issue. Now that you understand exactly what is wrong, see it happen with your own eyes. Don't set breakpoints, don't change the code, just run the project and see if you can duplicate the same behavior. It's important that you don't actually jump into the code until you see it happen. This is true for a number of reasons. One, the issue may have already been addressed. If you can't recreate it in the current version of the source code, then jump over to the last build on testing and recreate it. If you can, then you're in luck. Your issue is already fixed. Secondly, there are times where setting a breakpoint may actually prevent the issue from occurring, so recreating it before you stop the code is important just so you can see the error DOES occur, just not when you're debugging. So see that error with your own two eyes. Often seeing it, will help narrow your focus on what actually might be happening in your code.
3) Figure out what is causing the issue. This is where you start stepping through the code. We'll talk more about various techniques for this in a bit.
4) Figure out how you should fix the bug. Don't fix the bug, but THINK about how it should be fixed. Often you'll jump in with a solution and it may even be a solution that works, but it's not the right solution or it's not a solution that works in every case. Once you've seen the error and you've identified what's causing it, think about what options you have for fixing it and think about which one is correct for your given situation. Remember to take into account where you are at in the product lifecycle as well. Re-writing a function might be correct early in the development stage, but might be a poor decision late in the development life cycle. Bug fixes are often business decisions as much as coding decisions and it's important to remember that.
5) Fix the bug. Make the code changes you need to and eradicate that error.
6) Verify that you actually fixed the issue. Compile your code and attempt to recreate the issue. Also, take the time to run through a few other test cases just to make sure your fix did not introduce any new issues. Better to catch them now then to have to repeat this process all over again which can be time consuming and resource intensive.
There you go, the mini-life cycle of a debugging session. I'm pretty sure you didn't learn anything new from any of that, but I would recommend you try to think through each of those steps a little more this week. I know it helped me with a lot of my issues when I made an effort to do that the past couple of weeks. It gave me a renewed focus and really helped me think about what I was doing as I was tracking down my various bugs.
That BIG Step #3
Ok, so Step 3, figuring out what is causing the issue. Actually tracking down that bug in the code and seeing where the error is actually occurring. This is the one step that if you learn to do well and learn to use all the tools you have built in to Visual Studio, you can really increase the speed and ease in which you hunt down what is causing a particular issue.
Control Execution Flow
First up is controlling the execution flow of the program. This is by far one of the most commonly used features of Visual Studio to help debug an issue. We will go over the buttons on the Debug toolbar quickly just as a refresher for what each one does.
Continue - First up is the "Continue" button. When you've paused the execution, either by hitting the "Pause" button or by running into a breakpoint, this button will resume the execution of the code.
Pause - pauses the execution of the code. This will stop the program on whatever current line of code was just getting ready to be executed.
Stop - will stop the program and shut down the debugging tools.
Restart - will stop the program and then start it again
Show Next Statement - if you've went somewhere else in the code, clicking this button will take you back to the "Next" statement that's going to be executed.
Step Into - resume execution then pause again after the current line or at the beginning of any function the code enters
Step Over - resume execution for a single line of code and then pause again
Step Out - resume execution and then pause again once the current function has exited
Right-click options
When you are "Paused" you can also right click in the code window to access some other execution control options.
Show Next Statement - same as the "Show Next Statement" in the debug toolbar. It just can be accessed via right click as well.
Run to Cursor - this will cause the execution to run to the current line of code you have your text cursor in
Set Next Statement - allows you to jump the execution of the program to any line of code. This will cause the execution to skip any code between the next "Next" line and the previous "Next" line which could have unforeseen consequences in your program.
Breakpoints
Next up is one of the most common debugging tools used in Visual Studio. The breakpoint. When the program's execution reaches the breakpoint, the debugger will automatically pause the program every time. You can set multiple breakpoints, turn them on and off and clear them all. Breakpoints are extremely useful but can be extremely frustrating when you are trying to track down a bug that is happening in a loop or only when a particular value or condition is present.
That is where a second "special" type of breakpoint called a "Conditional" breakpoint comes into play.
Conditional Breakpoints
These were new for me and have made quite a difference in my debugging. To access Conditional breakpoints you have to set a breakpoint, then right-click on the breakpoint and this will bring up a context sensitive menu of breakpoint options. If you clicked on the red breakpoint circle, then pick "Condition" (if you right-clicked in the code window, then pick "Breakpoint", then pick "Condition") and that will bring up the "Breakpoint Condition" dialog. These breakpoints have a particular condition that must be met before the execution is paused.
Just about any condition can be entered. You can break when an object becomes NULL or you can break when a particular variable equals a certain value. Basically if you can write it in an IF...THEN statement, then you can write it as a condition.
You also have the option of not just checking to see if a condition is True, but you can also wait for an expression to change. If you're trying to track down when a particular variable is changing, this is a great way to nab that moment in time.
Hit Count
Hit Count is a great way of only stopping the execution of the program when you really want to. If you know the error is only occurring in the 5th pass through a particular method, then you can throw a Hit Count breakpoint in that method and tell it to only break when that breakpoint has been hit 5 times. You can also change the settings to break only on multiples of some number just to give you an occasional breakpoint, or you can set it to be greater than or equal to. Using Hit Count breakpoints are a very good way of tracking down those elusive bugs that don't occur on every pass through a method.
A World of Windows
Visual Studio has a number of tools that appear in various windows. These windows can be free floating or you can dock them into the IDE or put them in the tab bar. Each help in a different way in your search for what might be causing your particular issue.
Watch Window
The Watch window only appears when you actually create a "watch" on a particular object. The watch window itself will display the object you have selected to do a watch (when the code is paused, right-click on the object you want to watch and select "Add Watch") and tell you what it evaluates to in the current context. This will allow you to watch how an object changes as you move through your code.
Call Stack Window
The Call Stack window will list all of the methods the code is currently nested within. As a new method is called, it is added to the top of the stack and when a method is exited, it is removed. This is useful not only for figuring out what functions have been called previously, but you can also at a glance see what parameters were passed into each method and what their values were. You can also double-click on a method in the Call Stack window and you can jump to that point in code. Very useful for moving around through the code to examine what might have happened or move to a new place to set another breakpoint.

Output Window
This is where all messages generated by your program are displayed. This window becomes particularly useful when you write some code to "log" things to this window using System.Diagnostics.Debug and System.Diagnostics.Trace. Writing messages and the current values for objects to this window can be particularly useful if breaking the execution of the program causes the error to disappear or introduces a new one. While the Output window isn't used a lot for debugging, it's important to remember it is there and available for those times when it makes sense.

Immediate Window
The Immediate Window is probably used as much in debugging as breakpoints. This window is very useful for evaluation expressions and code to see what their current values are. Something that might not be as well known is that you can not only print out the current values for objects, but you can change the values for objects in the Immediate Window as well. This can be extremely useful and timesaving when you know your program errors only when an object contains a particular value.
There we go, just a quick refresher on debugging. Nothing ground breaking here just the tools and techniques that are available to us everyday that you might not have been familiar with or might have forgotten about. Debugging is a skill that we are required to use day in and day out as a developer so it's important to always keep an eye out for those tools, tips and tricks that might be able to help out. Of course, all the debugging tools amount to nothing if you don't understand the code itself. So dig in and develop that broader and deeper understanding of the language, the software and the nature of your business. All these will aid you in tracking down those issues. If all else fails, remember, it's probably just a user error.