On January 12, 2010, I gave a 90 minute presentation on code contracts to my coworkers. I presented the three lessons that are available for download at the following location ContractProgrammingLessons.zip. This file also includes the PowerPoint presentations that I used. I presented the argument that code contracts were a useful tool to improve readability, reliability, correctness, ease of diagnosis, and other software qualities. Later that evening, I presented these ideas to another friend of mine who is an active software developer. Here were some of the reactions I received and my responses to them. And in a few cases, I have noted the response I would have given if I had had the clarity of mind at the time.
Question: I already use something like preconditions
These preconditions look like something I already do using handcrafted tests that throw exceptions when arguments are invalid. How are code contracts an improvement over my debug assert statements?
Yes, preconditions function very much like your handcrafted assertions. If you are already testing for the correctness of arguments on entry to all of your methods and constructors, then the use of preconditions should feel very familiar. However, the use of the conditions from the code contracts library adds the possibility that automated tools such as the static checker can examine your code and detect possible defects even without automated unit tests.
What I wish I had also said:
The theory of preconditions is actually broader than simply checking for argument correctness. It includes the checking of all preconditions including the state of the current object as well as the state of any other related items. Again, you can achieve many of the results of using code contracts by using manually crafted assertions statements. But if you study the code contracts literature, and learn the theories of design by contract, you will have a richer and deeper understanding of what it means to design and construct correct software.
Furthermore, Microsoft code contracts can be associated with interfaces which allows all of the descendents to be protected by contract assertions without having to place such code in each implementation. This is something that is not so easy to do with handcrafted assertions, although it is possible with some effort.
Question: Do you have to leave contract runtime checking enabled even when you deploy to production?
No, there are a wide range of choices available to you to enable and disable code contracts. One of the options includes enabling preconditions and disabling postconditions. Technically speaking, a precondition has the same performance impact as an identical postcondition. However in practice, post-conditions are often more expensive to execute because they are testing different qualities of the system. In circumstances that require you to maximize performance, there may be situations when you would want to disable the postconditions, while retaining the runtime checking on preconditions.
Question: Is it mandatory that exceptions are thrown when a contract fails?
No, the behavior of contract failures at runtime is customizable. You could suppress the exceptions and write the information to an event log. However, before you choose to suppress the exceptions, keep in mind that contracts, by their intent, are expressions of what it means for the code to be correct. And if they fail, something is badly wrong with the code. You would want to seriously think before you suppressed the exception associated with a contract failure.
Question: Are there particular contract exception types that can be trapped?
No, the contract exceptions are internal and thus, cannot easily be discerned in the clause of a try/catch statement. This is by design. The intent of the code contracts developers was to discourage programmers from altering the behavior of their code based on a particular type of contract exception. This is in accordance with the philosophy of code contracts that they should not appreciably alter the logical flow of a program regardless of whether they are present or absent. Fortunately, it is easy to test contracts in an automated test framework by simply surrounding the test code with a try catch block and examining the exception to see whether the desired contract exception has been thrown.
What I wish I had also said: There is one other way to implement an automated test strategy that tests contract failures to ensure that they are working as expected. That method relies on coding a customized contract failure event handler. I am doing some experiments along those lines, and if I get something that I like, I will post a blog entry about it.
Comment: I dislike the placement of postconditions
The placing of the precondition at the beginning of the method body makes some sense. But placing the postcondition before the method body does not make any sense at all. And when you are single stepping through a program and you see the cursor jump around, it is very counterintuitive. Oddities like this may discourage some people from adopting the technology, which would be sad, because it offers tremendous potential to improve software quality.
You are correct. The placement of post-conditions and the resulting cursor behavior during execution is counterintuitive. Eiffel implements contracts in a much more intuitive and attractive fashion. I believe that it would be more intuitive to place postconditions at the end of methods, constructors, and properties where they apply. And you are correct that some people may avoid this technology because of its imperfections. But those of us who are familiar with contracts, and know the power of contracts to help us enhance the quality of our code, have encouraged Microsoft to release this product in its current form rather than waiting for it to become “perfect”. In the spirit of agile development, they are continually improving the product by getting feedback like this from actual users. If adoption of code contracts expands, and it demonstrates value in the development process, I would expect Microsoft would continue to invest in making it even better.
Question: Can you call methods as part of your contract assertions?
This is useful in cases where the condition to be tested is more complex than can be easily represented in an expression.