A few months ago, I discovered that Microsoft Research's Spec# project spawned a new item called Code Contracts, and I was pretty enthused about the technology (even though I didn't know much about it).
To summarize, Code Contracts allows you to create validation logic within your methods and classes without needing to write a lot of if/then statements. Even better, Code Contracts provides both runtime and compile time checking of this validation, which you just can't get from traditional validation code.
In preparation for my presentation next week at the Columbia Enterprise Developers Guild (June 10th at 6:00 P.M. for those in the Columbia, SC area), I spent some time with Code Contracts. I'm happy to report that Code Contracts exceeds my expectations.
Current status quo
The rationale behind Code Contracts might not be obvious to everyone, so I want to talk a bit about the current status quo of validation. Right now, validation code requires a developer to write a large number of if/then statements. By itself, that is not much of a problem; the statements are not hard to write. The problem is the logic does not stand out to the casual reader. It is hard to differentiate between validation code and actual work. In addition, this code is tedious to write and maintain. As a result, it is infrequently updated or forgotten altogether as business logic changes. Doing anything with the validation code other than throwing exceptions requires a lot of work, so developers tend to just throw exceptions (which the caller swallows or just logs like any other error). Finally, the code is indistinguishable from any other code to the compiler, which makes static analysis or specialized unit tests unlikely.
Imagine a method with the following signature:
static private int TraditionalValidation(int Input1, string Input2, List<int> Input3)The business logic for the validation on this method is that 0 <= Input1 <= 100, Input2.Length > 5, and Input3 must contain the value 500. Sample code A shows the validation for this. Sample code A
if (Input1 < 0 || Input1 > 100)
throw new Exception("Argument Out Bounds (Input1 must be between 0 and 100 inclusive)");}
if (Input2.Length <= 5)
throw new Exception("Invalid Parameter (Input2 must be longer than 5 characters long)");}
if (Input3 != null)
throw new Exception("Invalid Parameter (Input3 must contain the value 500");
This is an awful lot of code to do a very little bit of work.Let's add another stipulation: This function's return value must not be negative. Again, this will require another if/then block throwing exceptions (see Sample code B). Sample code B
if (Result < 0)
throw new Exception("Invalid return result (must produce output >= 0)");}
There are some classes that must have a way of determining if they are "valid" or ready. Often, the developer writes some sort of IsValid() method to perform the validation and calls it at the end of any method that changes the class' state. This becomes a chore, and it is easy to forget to include that call.
The Code Contracts difference
With Code Contracts, we get to skip all of the tedious code writing and exchange it for something much simpler. Code Contracts defines a static class called Contract that has two static methods for input and output validation: Contract.Requires() and Contract.Ensures(). Both should be placed at the very beginning of the method, and both take conditional expressions as their input parameters.
There are some restrictions as to what methods may be used within these calls, and some special details regarding loops and collections; the Code Contracts User Manual (which is surprisingly well-written, especially given the status of this project) has full details. Optionally, you can pass to Contract.Requires() and Contract.Ensures() text to be used in error messages.Sample code C shows the entire input and output validation of Sample code A and Sample code B combined. Sample code C
Contract.Requires(0 <= Input1 && Input1 <= 100);
Contract.Requires(Input2.Length > 5);
Contract.Requires(Input3.Contains(500));Contract.Ensures(Contract.Result<int>() >= 0);
The code is much clearer and more concise, and it stands out as validation code.
For the issue of validating object state, Code Contracts allows you to create a method and add the [ContractInvariantMethod] attribute to the method. The method must consist only of calls to Contract.Invariant(), which also accepts conditional expressions. Once that is done, the code in the method is used to validate the object at the end of any of the objects' method calls.
Using Code Contracts
Visual Studio 2010 Beta 1 ships with the Code Contracts in mscorlib.dll, so the namespace will be available "out of the box." However, to get the benefits of the Visual Studio integration, you will need to download and install the Code Contracts package. (There is an academic license and a commercial license, both of which are free.)
Next, you should make sure that you add a reference to the Code Contracts assembly. Classes that use Code Contracts should add a reference to the System.Diagnostics.Contracts namespace.
Finally, you will see that your project properties has a tab added to it for Code Contracts; you use this property page to enable/disable Code Contracts for runtime checking and static analysis. In addition, you can control their settings of these two systems on this property page.Important notes: The configuration is tied to your compilation settings; this means that you can selectively disable functionality for release builds so that your production code does not contain pre-release code (the Code Contracts is not a final release yet). In addition, the validation has some overhead, and its default behavior (as described below) is not desirable in most production applications.
If you prefer, you can get the benefits of Contract.Requires() without needing to rewrite any code under many circumstances. If you have a method in which the initial statements are a group of if/then/throw statements with no else clauses, and those statements meet the requirements of Contract.Requires(), you can add a call to Contract.EndContractBlock() after the group of statements. Code Contracts will then treat that group of statements as preconditions, just as it does with Contract.Requires().
With invariants, any properties used in the validation should be explicitly declared, and the underlying value (not the property) should be tested. My testing shows that not doing this caused validation to occur before all needed properties had been set.
You may be wondering what happens with the runtime checking. My initial thought when using Code Contracts is that an exception would be thrown. Talking to a friend of mine, he assumed the same thing. We are so accustomed to throwing exceptions in our code for validation that we don't realize there might be a more useful way of handling things. Code Contracts implements a better way!
When the code is compiled, the Code Contracts system (if enabled) rewrites the code a bit. First, an exception (no pun intended): If you pass Contract.Requires() error message text, it will change from the default behavior to throwing an exception using that text. Aside from that special case (and when certain exceptions are raised, as per the documentation), what happens is the rewriter has a failed contract call, the ReportFailure() method. Don't worry, the method is automatically generated; if you like, you can override it with your own. The default implementation raises the event RaiseContractFailedEvent. If there is no handler for that event, it calls the TriggerFailure() method (you can provide your own implementation), which breaks the application to the debugger. So, while the system does not throw exceptions (in order to bring the errors to the attention of the testers and developers), it is trivial to provide that functionality if you prefer. Alternatively, you can modify the runtime checking to throw errors instead with a checkbox on the Code Contracts page in the project properties.
Code Contracts' static analysis checks the code when it is compiled and looks for red flags. Due to the nature of the beast, it's difficult for the static analysis to be perfect. Instead of claiming that your code will not work, it declares that a contract is "unproven." You see the warnings in the "Error List" window in Visual Studio.
By default, the static analysis is off because it's a very intensive process, but you can enable it in the property page. Because the static analysis can generate a ton of warnings that are not pertinent, the system allows you to define a "baseline" XML file of errors. When you include this "baseline" file in the analysis, it will not generate warnings about the items in the baseline. This is a handy feature that allows you to make sure that you are only seeing new, unknown warnings.
This is but a brief overview of Code Contracts; I didn't highlight every minor detail for the sake of brevity. Fortunately, the manual is well-written, and the system is not complicated to use at all. This is one of those rare instances in which it takes only a few minutes to learn to use something with huge, immediate benefits.
While the code is not considered a final release at this point, the ability to turn it off for your release builds entirely mitigates the risk. If you're a .NET programmer, I believe that you should take 30 - 60 minutes to learn this extremely useful new framework.
J.JaDisclosure of Justin's industry affiliations: Justin James has a working arrangement with Microsoft to write an article for MSDN Magazine. He also has a contract with Spiceworks to write product buying guides.
———————————————————————————————————————————-Get weekly development tips in your inbox Keep your developer skills sharp by signing up for TechRepublic's free Web Developer newsletter, delivered each Tuesday. Automatically subscribe today!
Justin James is the Lead Architect for Conigent.