Design by Contract Adapted from Object-Oriented Software Construction by Bertrand Meyer In relations between people, a contract is a written document that serves to clarify the terms of a relationship. The most distinctive feature of a contract is that it entails obligations as well as benefits for both parties. A method call is a formal contract between the caller and the supplier method.. The precondition binds the client: it defines the conditions, which a call to that method is legitimate. It is an obligation for the calling client and a benefit for the supplier method. The post-condition binds the supplier method: it defines the conditions that must be ensured by the method on return. It is a benefit for the calling client and an obligation for the supplier method. The benefits are, for the client, the guarantee that certain properties will hold after the method call; for the supplier method, the guarantee is that certain assumptions will be satisfied whenever the method is called. The obligations are, for the client, to satisfy the requirements as stated by the precondition; for the supplier, to do the job as stated by the post-condition. In addition there may be certain consistency conditions, which have to be satisfied as part of the contract. The consistency conditions ensure that everything is done legally. Note that the precondition is a benefit for the supplier. If the client’s part of the contract is not fulfilled, that is if the caller does not satisfy the precondition, then the method is not bound by the post-condition. The advantage of this is that it considerably simplifies the programming. Having specified as a precondition the constraints, which calls to the method must observe, the developer may assume that the constraints are satisfied. Erroneous parameters do not have to be tested for and somehow dealt with DBC Rule : A method will not test for and handle a failed precondition. This rule is the opposite of what is usually called defensive programming. DP advocates the idea that to obtain reliable software every component should protect itself as much as possible. Better check too much than too little. A redundant check might not help but it will not hurt. DBC follows from the opposite observation: redundant checks can and do hurt. Complexity is the major enemy of quality; Simplicity becomes a central criterion. From this perspective, possibly redundant checks do not appear so harmless any more. Extrapolated to the thousands of methods of even a medium-sized system the sheer number of redundant code turns into a morass of useless complexity. Redundant error checking code means more program lines means more complexity means more things that can go wrong means more error checking and so on.
With DBC preconditions, post-conditions, and consistency conditions are identified and the responsibility (client or supplier) for enforcing the condition is explicitly specified. Our goal should be to obtain the best possible reliability. For a system of any significant size the individual quality of the various elements involved is not enough. What matters is the guarantee that for every interaction between two elements there is an explicit list of mutual obligations and benefits specified in a contract. The conclusion has the form of a Zen paradox. To produce more reliable software, one should sometimes check less. DBC Rule A precondition must satisfy the following requirements. The precondition appears in the documentation available to authors of client modules. It is possible to justify the need for the precondition in terms of the specification only. Every feature appearing in the precondition must be available to every client to which the method is available. DBC Rule A precondition violation means that the method’s caller, although obligated by the contract to satisfy a certain condition, did not. This is a fault in the client. If a precondition violation occurs, the method should not be executed at all. The method has stated the conditions under which it can operate, and these conditions do not hold. Attempted execution would make no sense. DBC Rule A post-condition violation means that the method, presumably called under correct conditions, was not able to fulfill its part of the contract. If a post-condition violation occurs the method should terminate execution, clean up if possible, and report failure to the caller. Under no circumstances should a method pretend it has succeeded when in fact it has failed to achieve its purpose for what ever reason. A routine may only succeed (having experienced no problems or perhaps after experiencing some recoverable problems (retry network connection for example)) or fail.
Ideal method structure Consistency check ------ system is initially consistent Precondition check ---- caller satisfies precondition Method processing --- method performs its job Post-condition check --- method accomplished its purpose Consistency check --- system is finally consistent ………………………………………………………..
The primary java mechanism used for DBC is assert. Note that assertions are disabled by default. They are enabled via java –ea when running the system or by setting the classloader to enable assertions. Precondition, post-condition, and consistency requirements are usually implemented as Boolean methods. These methods are very useful for DBC assertions and also for Unit testing. They should become a part of all development.
Although it is important to include preconditions, post-conditions, and consistent conditions during development, it is not always practical to include all DBC code in a final product. DBC checking may be relaxed based on the amount of trust that can be placed in the code at a particular point. The following are some suggestions from safest to least safe. 1. The consistency check at the beginning of each method may be disabled since the consistency check at the end of the method guarantees that the object’s state will be valid at the start of every method invocation. It may generally be trusted that the object’s state will not change between method calls so consistency checks will only appear at the end of a method. 2. The post-condition check may be disabled if previous unit testing verifies that the method is working properly. Since the consistency check monitors the state of the object, the post-condition check only monitors the processing done by the method, and therefore may be discarded in favor of unit testing. Unit testing will not be as safe as run time postcondition checking, but it may be safe enough, especially if one has confidence in the method code. 3. The consistency check at the end of the method may be disabled if there is enough certainty that the method does not place the object into an inconsistent state. 4. As a last resort disable precondition checks. This is the least safe and least advisable, because although one knows and can control the code personally written, there is no control over what arguments may be passed to the method. However, in a situation where a) performance is desperately needed and profiling pointed at precondition checks as a bottleneck and b) there is some kind of reasonable assurance that the client calling the method will not violate preconditions (as in the case where the client code is also personally written) it may be acceptable to disable precondition checking.