posted on Wednesday, June 02, 2004 2:58 PM by roydictus

Assert Yourself (Part I)

Asserting yourself is a best practice. Especially when you write code. Or rather, you should assert that your code is correct.

What I'm talking about, of course, is not psychology or assertiveness, but correct and abundant use of Debug.Assert. This wonderful method, which dates back to the old C days, is executed in Debug versions of our code and verifies whether given assumptions are true. If not, the code exits and writes an error message to the Debug output, which we can read in Visual Studio.Net or which we can log to a text file, for example, using a TraceListener.

Misconceptions about Debug.Assert?

Misconception: Debug.Assert is for input parameter validation only

Hold on, hold on. Yes, I'm sure most of us know Debug.Assert and that many developers use it, maybe all the time, for input parameter validation on non-public methods. It's excellent for that, as is illustrated in this example:

Example 1

   1:  protected static double OptimizedLength(string text, int start, int end) {
   2:      Debug.Assert((text != null) && (text.Length > 0), "OptimizedLength: Input 'text' is empty.");
   3:      Debug.Assert(start > 0, "OptimizedLength: start is out of range.");
   4:      Debug.Assert(end >= start, "OptimizedLength: end is not after or equal to start.");
   5:   
   6:      //Rest of code here
   7:  }
 
But it can help us even better! Debug.Assert, in my humble opinion, is the most underused tool available in the .Net world, while it should, in fact, litter all code. Even in Microsoft's own example code, there's hardly any trace of it (pun unintended). It seems that us developers have some misconceptions about it, or fail to see the full range of its applicability.
Example 2

Consider this simple piece of code:

   1:  XmlNode pathNode = node.Attributes["HintPath"];
   2:  string xmlPath = pathNode.Value.Replace(".dll", ".xml");
   3:  Console.WriteLine("XML Path: " + xmlPath); 

What's wrong here?

If anything goes wrong during execution of this code, it's hard to tell why exactly. The author assumes that the XmlNode called node exists, is non-null and contains an attribute called HintPath. There's no doubt. If, due to a bug somewhere, one of these assumptions is wrong, the code above fails and it's hard to figure out which assumption was wrong.

Unless the author uses our friend:

   1:  Debug.Assert(node != null, "Node is empty before reading HintPath.");
   2:  Debug.Assert(node.Attributes != null, "Node Attributes are empty before reading HintPath.");
   3:  XmlNode pathNode = node.Attributes["HintPath"];
   4:   
   5:  Debug.Assert(pathNode != null, "Path Node is empty before determining XML Path.");
   6:  Debug.Assert((pathNode.Value != null) && (pathNode.Value.Length > 0), "Path Node is empty string.");
   7:  string xmlPath = pathNode.Value.Replace(".dll", ".xml");
   8:   
   9:  Console.WriteLine("XML Path: " + xmlPath);

Now, if something causes any of the assumptions to be off, whoever has to debug this code knows about it as soon as it happens. And of course, the cause of the error will show up on the test report. This is a tremendous help when debugging.

Misconception: This is too much work!

Ouch--the old argument that quality assurance is too much work. I agree that it's no fun, and that it seems to bog down developer functionality (just like that other thingy that's too much work: unit testing), but the fact is that it doesn't. Smart developers (that is, those who write unit tests and asserts) spend much less time debugging their code than others simply because they know where to look when something goes awry. An informed developer is worth two, you could say.

Adding asserts doesn't add much work to the load of development. It's not like adding an assert is as complex as figuring out a new sorting algorithm, and it doesn't take much time to type, especially with IntelliSense.

Misconception: Debug.Assert slows down my code

This is and is not a misconception. Debug.Assert statements only show up in the Debug version of your assemblies, so they don't slow down your Release code. But, of course, they do slow down Debug code.

There's nothing really wrong with that, unless your code is extremely time-sensitive. But if it is, probably you're not doing much logging, if any. Time-sensitive code is hard to debug, but that's another story. In most cases, the slowdown caused by ubiquitous Debug.Asserts doesn't matter much--especially considering the benefits. And if you're ready to stress-test your app, simply stress-test the Release version.

Incidentally, if you don't believe Debug.Assert only shows up in Debug assemblies, disassemble your Debug and Release assemblies and see for yourself!

Comments