Thursday, June 16, 2011

Reflections on my Code Contracts experience

Microsoft has half-baked in Code Contracts to the .NET framework. Although having language-independent support for Code Contracts is a great step forward, widely available static analysis tools are the piece that makes contracts worthwhile. Until Code Contracts are available at the Visual Studio Professional level (it current requires the Academic or Premium versions) widespread adoption will not take hold.

I have been lucky enough to work with Visual Studio Ultimate so I’d like to share my experience of several months of working with contracts. This is based on my experience with release 1.4.31130.0 (November 30, 2010) which is not the current version (currently a Pi day release!). These tools are a community release, not a fully integrated final version so I won’t focus on the relatively few bugs or missing features.

I started with bringing up the adoption of contracts because of a beneficial snowball effect. Having an open source and commercial project use code libraries allows me to use, not abuse, their APIs. I think this is especially true for open source projects because developers like to write code, not documentation. Test driven development has been a boon for open source documentation, a benefit that doesn’t get the attention that other TDD benefits do. I can look at the tests to help understand how to use the code. The more documentation that can be incorporated as source code, the better developers who use a given library will be. Having contracts in place with static analysis can effortlessly (aside from slower compilation)push feedback to the developers, minimizing the effort developers need to take pull information based on reading code, comments, and documentation. Microsoft’s adoption of contracts within the .NET framework has already been helpful to me in preventing bugs. I am not talking about documentation in the conventional sense here, although I address that point below.

I have found it useful to switch between synchronous and asynchronous static analysis. If I really want to get the maximum benefits of contracts in an area I use synchronous analysis, where my build completes only after the static analysis is complete. However, the extra 5 to 10 seconds of compilation, in my development keeps me from keeping static remaining synchronous analysis be a permanent setting. I have to be in a coding area where I feel significant contracts benefits before I turn on synchronous static checking. This may seem like a small point to be focusing on one specific setting, but I feel usage patterns of synchronous analysis can be a great metric to see what a developer perceives as an ad hoc cost-benefit analysis of using contracts. I am sure many developers do have one consistent process and settings usage, and for those this wouldn’t be as good of a metric, but I am always a knob twiddler myself.

One way of classifying the development I do is between highly-reusable code and application code that I don’t find the cost-benefit of high reuse to be compelling. Code reuse is constantly cited benefit of OO programming but that benefit is often not significant enough to outweigh its cost. Reusable code often involves dealing with levels of abstraction that can make grokking using this reusable code take some time investment. My rate of line of code generation for reusable code is much, much lower. When you provide a library for others to use, you have to be prepared for every possible kind of abuse be made by callers. For less-reusable code, the level of paranoia in trusting the calling object can be reduced. In areas like null-checking this can be a tremendous use case for code contracts. I can assume that, for example a sequence of method calls that must occur in order, are being utilized by a developer more familiar with this codebase. They may still screw things up but my handling of mistakes can be simpler without trying to correct the misuse or going through significant effort to make clear exactly what the mistake was and how to rectify it. The sequence of methods calls is an example, though, of where contracts aren’t applicable, which I’ll expound upon below. Also, coming up with naming conventions and other forms of consistency is no mean task, as the very useful Framework Design Guidelines book illustrates.

Actual generated documentation can be another thing provided by Code Contracts, which is one of the bullets Microsoft has used as a selling point for contracts. I find the above split between highly reusable code and less reusable code to be applicable here to. I find this kind of documentation beneficial for highly reusable code, and less so otherwise. I feel the same way about XML documentation as used provided as input to tools like Sandcastle. When I am writing reusable code I try to write useful XML documentation but when I am not, I abhor writing code with it. I find it just clutters the code and too often I fall into the trap of not always writing comments that are truly meaningful. It can be too easy to rely on GhostDoc, wonderful tool that is, to provide documentation with zero value added. At the moment, the stable Sandcastle release doesn’t support processing code contract documentation. The Sandcastle project has a patch to support this, but I failed to get that working, and rolled back to the stable release.

Writing code that utilizes contracts leads one to a more functional approach, rather than an OO one. My experience with pre and post conditions was more immediately fruitful than my use of object invariants. When I focused on not having side effects and not storing state in objects, that is the scenario where pre and post conditions are valid. Any possibility of side effects limits or eliminates the applicability of this variety of contracts. In my example earlier in this post, a scenario where I relied on a sequence of method calls being made relies on object state to work, and is beyond the scope of where contracts can help, at least today’s version of contracts. In the much smaller time I have played with object invariants, I didn’t get static analysis findings that I had hoped for. It is quite possible that this just requires more effort on my part to obtain benefit there. Interestingly, although I see contracts being awesome for functional programming, it seems like the current state of f# support may be lacking as this blog post suggests.

I have found myself deciding what classes go in what assemblies partly based on whether I am using contracts. Code contracts can provide a lot of data to either treat as warnings or errors. Employing implicit non null checking for example, means that calling code will need to do a LOT of error handling. In a less reusable scenario, it can be convenient to have null checking done by the called code in one place, rather than in each piece of calling code. In such a scenario, I would still check for contract usage based on other assemblies, I would just not create contracts for the classes within this assembly.

To get serious with Code Contract usage requires dealing with a large volume of warnings. Unless you are in a situation where 100% compliance is pursued, there will be warnings that you’d like to disregard. Code Contracts attempts to deal with this through using baseline files. These represent a list of warnings previously observed to be disregarded. I didn’t spent much time trying to use this feature but when I tried I couldn’t get it to work. Another option available is using the ContractVerification attribute to allow classes, methods, or even assemblies to selectively be ignored or verified.

Code Contracts is a really compelling feature. At this time, provided my employer has the license for static analysis, I will continue to use Code Contracts for high reuse code. Since I only have professional at home, my side projects will go without Code Contracts. Until Microsoft decides when and how to fully include Code Contract support within Visual Studio, I am leery of an “all-in” Code Contract usage for a team.

No comments:

Post a Comment