Wednesday, July 13, 2011

Debugging Code Techniques In VS.NET 2010

OK so you have a problem in code either during development, testing, or production and do not know exactly how it is occurring. What do you do? For those of you that are thinking your code does not have problems or there should never be problems in the 1st place, please click here. For the rest of us in the real world, you might be thinking about a new tool like 'Intellitrace' to track down exactly when the error occurred. But not everyone has that environment created and even with using it, you still need to figure out *why* it occurred. How do we do this... DEBUG the code!

So now a lot reading this might think, "Well yeah I know all about debugging, simple stuff." That may be all and true but it surprises me how many developers out there based on questions I see asked a lot from an array of environments only know (2) buttons on the keyboard when it comes to debugging: [F10] and [F11] (Step Over & Step Into with default key mapping). Oh yeah and [F5], Start!

To be good at debugging and playing detective to track down problems or anomalies that cause problems, Microsoft has provided us with a plethora of debugging options within VS.NET. Most of the techniques have been around for multiple versions of VS.NET and *some* of the techniques still not known by a faction of developers stretches all the way back to the old VB Visual Studio IDE.

So let's review the (3) most basic debugging techniques: Step Into [F11], Step Through [F10], and Step Out [Shift + F11]. Step Into [F10] will execute each line of code, going into any method, property, etc. call. This is the most granular way to trace each line of code. Step Through [F10] will *not* go into code that makes up a property, method, etc. and rather execute that code completely without executing line by line, returning control to the developer to debug the next immediate line of code after execution has completed. The last one I mentioned, 'Step Out' [F11] is one I find under used even though this is functionality that stretches back to VBA and VB6 (ever watch someone hold down the F10 key or press it like they are tapping on a snare drum to exit out of a method?). What this does is allow the developer debugging to exit out of the method immediately allowing control to be passed back to the next line of code
after the calling code to the current method was made, but still completes execution of the current method, property, etc.. This works well for the following example - let's say you have a method you are debugging and it is 50 lines of code. You need to understand what is happening between lines 5-10 and the rest is not important for what you need to know. What you would do is press [F11] to step into the method to debug and gather the information needed, but once you were finished observing lines 5-10 you want to return execution back to the caller but yet finish execution of the current method. You can do this by 'Stepping Out' of the routine by pressing [Shift + F11]. A lot better than placing a break point the line after the caller and pressing [F5] or trying to press [F10] another 30x to finish the method.

This really so far is super basic stuff and hopefully a bore or quick review to any intermediate or seasoned developer. But you know as well as I that the hard to track down issues, 'anomalies' happen all too often and there are a lot of other ways to debug and track down issues. One way I discussed previously is by using conditional breakpoints which I talked about in the following post:
How to: Set a conditional breakpoint in VS.NET Ever press [F5] over and over hovering over a single variable value until the last name is 'Smith' or the value is 'x'? Well setting conditions on breakpoints to only stop execution when that condition is = True is well worth reviewing.

There are also several 'helper' tools that go along with debugging to help make the debugging process more efficient. So let's begin with a few tools to help with debugging. The 1st is 'Debug Labels'. Labels on debug points are useful to define descriptions or add attributes to help with individual breakpoints to provide information about it. This will carry over and be quite useful when exporting breakpoints as I will show next. So to begin, bring up the breakpoints window. The easiest way to do this is to press [Ctrl] + [Alt] + [B] on the keyboard. The window below shows this:

The Windows shows all active breakpoints and provides several sorting options and customizable features for breakpoints directly in the window. I will not go through them all here, so take a look and explore yourself. One
very important feature to take note of in this window, is that any action you select to preform on the breakpoints will only be carried out on the actively displayed breakpoints as a result of any searches you have made. So If you have 10 total breakpoints, and preform a search that reduces the list down to 3 breakpoints, only those 3 in the search results will be acted upon. To clear any search criteria, press the 'X' to the right of the 'In Column' selection list.

In the block of code above I have set (2) breakpoints and notice they both display down in the Breakpoint Window displayed previously. What I want to do is create a label and assign it to this breakpoint. There are (2) ways to do this: either right click the breakpoint in the code editor or in the Breakpoint Window to bring up its options Window and select '
Edit Labels...'

To add a label, type in a description or attribute, and press 'Add' as shown below. There is a 64 character limit, and you can not have commas. You can add as many label descriptions through the window at a given time, and assign as many labels as you want signified by the checkbox(s) selected to the left of the requested label(s). These labels
will be available for assignment to other breakpoints as well:

Once a label is created it can be assigned to 1..n breakpoints. Maybe you have a set of breakpoints that are similar and all need the same label. Another possibility is you have some sort of numeric order description. In this case the sorting ability in the Breakpoint Window is nice. Just sort the column to get the label description in order. This can help with a set of imported breakpoints or for walking through your own defined breakpoints. From this window you can search through the breakpoint labels as well. Just change the '
In Column' value to 'Labels', and type in the search criteria. The list will filter down based on the search results.

The next feature available from the Breakpoints Windows is the ability to Import and Export the breakpoints. Have you ever had that app you get out of source control and think "
Ok I need to place (x) # of key breakpoints here, here, and here to do some task." Well what you should be doing is exporting your breakpoints and saving that file in source control. This is also really useful to pass along to other developers that might be working on your project. How nice for them to have descriptive (labels) pre-defined breakpoints already defined for debugging. The task is trivial: just press the save disk icon from the Breakpoints Window and the debug breakpoints will be exported to an .xml file. The import is just as simple. Just press the Import icon and select the .xml file where the breakpoints are defined. Don't forget to add these files to Source Control.

The next debugging technique helps with monitoring specific values but not having to stop execution to do so. They are called 'Tracepoints'. Have you ever been in a situation where you need to monitor a value of a variable and began writing 'Debug.Writeline' statements? Errrrr, No. Just use a tracepoint and monitor the same Output Window. This way you don't have to clutter up your code with debugging lines that later you might clear out or have to wrap in conditional #Debug statements. To create a tracepoint right-click on the actual breakpoint in the code editor or from the Breakpoints Window and select 'When Hit...'.

This will bring up a dialogue that allows you to type in some expressions to output needed information.

For example look at the following basic loop below.
For i As Integer = 1 To 10

I want to place a tracepoint on the variable to see it's output in the loop. The expression I will use is as follows:

The value of i = {i}

In my case I will leave the option checked to 'Continue execution', so I can view the output, but not have to stop execution. Notice after adding the expression your traditional breakpoint is now a tracepoint which is displayed as a diamond.

Before executing the code, make sure to have the 'Command Window' present. If it is not, you can access it by pressing [Ctrl] + [Alt] + [O]. Now execute the code that will run through the configured Trace Point. Notice execution will not halt, but the expression you provided will be output to the Command Window. Notice for the simple loop, it output all of the values.

Pretty nice and all done through a tracepoint. No need for custom logging, Writeline statements, etc. This is an especially good technique for watching values during their lifetime throughout an application and helps solve the old "I swear I clear that value out...", or "Why does that variable loose value here but have value over there...', and many, many more examples.

The last (but by
far not the last available technique) topic I am going to cover are 'Pinned Data Tips' while debugging. Ever hover over a value and have to remember it for later in execution, or jot down some notes about a particular debugged line of code? Well this feature is for you then. Begin by placing a traditional breakpoint on a line, and being execution of code until the breakpoint is hit. When you hover over the variable you will get it's current value. Ever notice there is a push pin on the end of the value? Yeah, go ahead and press it as displayed below.

To move the data tip around, just click and hold the pin to drag it off to the side if needed where there is more white space. You can also add comments to that data tip. Just press the down arrows, to get a text box for typing brief comments.

Notice as execution continues, or when you being a new debugging session the pinned data tip is still present! How cool, no more stickys on the screen or desk with random notes, values, etc. Notice how you will see it displayed as a blue horizontal push-pin in the pane where breakpoints are assigned in the editor. If it is on the same line as a breakpoint it will be mostly hidden.

As mentioned, once you being debugging again (even after stopping execution), you defined push-pins will reappear but there is one more useful added feature. Notice how the push-pin will display the
last debugging session's value. This can be really useful to see how the code reacts to different input possibly, and doesn't require you to keep track of what the value was from the last time code ran through this breakpoint. The last value is displayed below:

Note: to clear any data tips, right-click the push-pin in the code editor and select 'Clear'.

These debugging techniques are just a small sampling of all of the available features. Feel free to add comments for any other features you find useful as well. The main point to drive home is that to be successful in software development will at one time or another require 'playing detective' and tracking down unknown issues, anomalies, or maybe just learning how code behaves line by line. To do these tasks well you have to be efficient at debugging. So if you are one of the few that admits they only knew about (2) or (3) Function keys used for debugging, try some of these and many other documented debugging techniques to help you expand your problem solving abilities in VS.NET.

1 comment:

  1. In the "Tracepoints" section window is Output not Command/Immediate... just a quick ovservation. Nice and helpful tips... thanks.