Friday, August 5, 2011

Why Don't YOU Use Design by Contract?

I spent quite some time explaining why I think design by contract is such a useful methodology, and why every programmer (and especially those using object-oriented programming) should use it.  So why isn't it more widely used?

One obvious reason is the lack of education about design by contract.  You can find many university-level courses on object-oriented programming that hardly mention design by contract, or not at all.  Naturally, people who don't know about it aren't going to use it.  But the problem is deeper; I know that many of my own students don't use design by contract regularly.  It may be that I wasn't able to convince them that it is really useful, but I know I'm not alone in this situation.  I believe that for any methodology to be practically useful, it must be supported by tools that make its application not only painless but also rewarding.  And tools for design by contract are not yet at a level that promotes wide use.  Also, since programmers need instant gratification (see Programmers as Children), they need tools that will help them immediately, not only in some unforseeable (yet inevitable) future where the bugs they are writing now will come back to bite them.

I firmly believe that design by contract is useful even without any tools.  But consider the amount of work required to use it.  First, you have to write contracts for your methods.  As I said before, these don't have to be complete, but they do have to capture those parts of the contract that are likely to cause the most trouble.  Often, these are not deep properties of the computation.  On the contrary, these are things like whether an argument to a method is allowed to be null, whether a string or an array may have zero length, whether a number has to be positive, and so on.  This is not difficult to write, but write it you must.  Then, you need to look at this contract whenever you call a method, and consider whether your call is correct.  (Of course, if you don't bother, you will find your mistakes the hard way.)

But the most painful part of almost all methodologies arises when something needs to change.  Whether your requirements have changed, or whether you are just refactoring your code, you will need to change some contracts, and create new ones.  Then you will have to check whether all existing calls obey the new contract (or find out the hard way, as is the normal custom).

There are many opportunities for automated tools to help, at different levels .  To begin with, you will want syntax checking of your contracts.  This includes checking whether all preconditions can be evaluated by every caller; this is a must, since you can't require callers to obey conditions they can't evaluate.  You may also want your IDE to provide syntax highlighting for contracts in a similar way to what it does with code.  A "contract view" that shows just the contracts for a class would be nice, especially if it could show various views of the contracts.  Such views can include the client view (where internal parts of the contracts are hidden), and the provider view (where everything is shown).  The views would be customizable, for example, by showing only direct class members or all members (including inherited ones).

At a more semantic level, you want your contracts to be checked while you run the program.  This has great value in catching errors close to their sources.  However, instrumenting a program to check contracts is not trivial.  Beyond the difficulties of instrumenting any program, the semantics of the contract require some tricky handling.  One example is the ability to reference in postconditions the value of expressions on entry to the method, which requires tools to compute this value and keep it intact until the end of the call.

More generally, you may want a tool to help you verify the correctness of your implementation based on the contracts you write.  Software verification is still an open problem, but it is a very active area of research.  Part of this research is focused on verification of contracts.

Turning now to the question of change, tools that help manage contracts when the code changes are a must.  Such tools can modify existing contracts as well as create (draft) contracts for new code.  This is by no means easy.  Analyzing an arbitrary piece of code to extract contracts from it is an open (and very difficult) problem, although some progress has been made on it.  The problem is easier if some information about the intent of the change is available.  This can happen in refactoring; when you invoke a refactoring such as Extract Superclass, the tool has an indication of your intent, and can use this information together with existing contracts for the class (or classes) you are generalizing in order to create the contract for the new superclass.

Needless to say, the Eiffel programming environment has the best tools for design by contract, although much more is needed.  In future posts, I will describe some of the work my students and I have done on creating tools for design by contract in Java.