Friday, May 29, 2015

Debugging 101

Often times I heard from developers (not all of them juniors) the question "how do I debug this?"
Let me begin at the conclusion - use your experience. Most of the times when you have enough experience you can go directly to the source of the misbehavior and fix it.

This post is about the how to get the experience.

First thing to do is to understand the bug. Easy? Not at all. Just the other day we got an error stating "the dates are incorrect." after trying to explain to the user that created date, end date, and effective date might defer we've found out that the user had a totally different error. The original error was missing data, the description for the bug included so many misleading directions that we got lost on the way. Luckily, experience taught us to ask first.

Once you fully understand the bug, it's time for the second step - reproduction. Now this thing might be hard (or nearly impossible when it's a stress related bug), but it's by far easier to debug on your machine then on the lab 5 floors below ground, next to the "devil" called lab-manager, and his "minions" co-workers.
Note that in some cases the only way to reproduce is by using a non-development machine. While not being as easy to debug, it's still a good reproduction.

Now that you managed to figure what you want, and where to test it, we can advance to the third step - checking the code.
It's important to understand, before trying to debug and fix the code, check it. If there's a candidate for the bug's location, mark it (or add a log line to verify your assumption). Note there might be more than one location, mark them all, it saves time.

Step four. Now it's time for the real debugging. After we finished the setting up we run the scenario and verify the preliminary assumption. Hopefully we've caught the culprit, in case we haven't, return to step 3, there are more locations which are hidden.

Step five - the fix. This is the most dangerous step! Fixing a bug is prone to opening a new one in an unrelated location. Assess carefully the impact of the change, consult with others, and try to explain to someone (even your dog) what you are going to do. Usually we do shortcuts on this step, especially when the clock says 2:00AM, but it backfires at us always.

If all passed successfully, we're good to go. Call the QA, say we fixed it, explain the impact, and let them do their magic. Hopefully no new issues arise and we can ship it out.

A quick example. I'm using this code as the "buggy" program.
1 class Program
2    {
3        private class HelperClass
4        {
5            public List StringsList { get; set; }
6
7            public void PrintStrings()
8            {
9                foreach (var str in StringsList)
10                {
11                   Console.WriteLine(str);
12                }
13            }
14        }
15
16        static void Main(string[] args)
17        {
18            var helper = new HelperClass();
19            helper.PrintStrings();
20        }
21    }

The user would come to us stating "IT DOESN'T WORK!!!"
This code can't work, it's lousy and if someone would give it to me, he'll find the way out within the next minute. But "doesn't work" is not the error it gives. "Null reference" or "object reference" is the error message we're expecting to be given by the user. After we'll see the demo of what he did, we'll have it.
Step 2 - reproduction. In this case it's easy, run it on the developer's machine, it will fail.
Step 3 - find the candidates, in this case it would be lines 19,9 and 11. Either print a log or put a breakpoint on those lines.
Step 4 - debug. The debugger would stop on line 19, afterwards on line 9, but line 11 will never be reached. Further investment shows line 9 fails, StringsList is null.
Step 5 - fix. In this simple case the fix might be adding
helper.StringsList=...
or checking for null before the printing
if (StringsList==null) return;
or surrounding with try catch (bad idea, but fixes the bug).
Once we fixed the code, it's time to deliver it. Now the user can check it on its own.