Design by contract
Design by Contract (DbC) is an explicit technique in OO Design that seeks to define a metaphor for the design process. It provides a more generalised case of the Liskov substitution principle. The underlying belief of this technique is that programming constructs, particularly methods, should have their behaviour defined such a way as to provide a "contract" to their usage. This contract is comprised of:
- Preconditions - the state of the program that needs to exist before this construct (method) is allowed to be called.
- Postconditions - the state of the program after the method has been called.
- Invariants - those things that will not change due to the execution.
In the case of subclasses, the contract must be upheld, though it can be modified in a set manner. Preconditions must be at the same level of requirements or less stringent. Post conditions must provide the same or more. This leads to the maxim, "Require no more, promise no less."
Contents |
History
Bertrand Meyer coined the term "Design by Contract" while working on the development of the OO language Eiffel in 1986. The term was successfully trademarked in 2004.
Implementation
If a language does not have the facility to specify pre and post conditions in the form of binding requirements, documentation should be provided to explicitly state the pre and post conditions.
Acceptance
There is no consensus among developers as to whether this technique/maxim is useful. Among those who accept this idea, there are different schools of thought. Many believe that this technique should be strictly applied to all parts of a design, others believe that this technique is too restrictive for general usage and as such should only be used for critical components such as system APIs.
Worked Examples
The "Contract" part of Design by Contract is a metaphor relating real-world contracts. For instance, a Acme Construction may sign a business contract to build a skyscraper, for a price of $100 million. Legally, the contract means that Acme Construction must build the skyscraper to at least the standard agreed, and may demand $100 million dollars (but no more) as payment.
If we consider this business arrangement from the perspective of Acme Construction, we can regard the contract as a set of preconditions and postconditions:
Preconditions: The building must be built on time and to the required standard.
Postconditions: Acme Construction must receive $100 million dollars.
Acme Construction is free to build the building to a higher standard (if they want to) but not a lower standard. Also, they might choose to accept less than $100 million dollars as payment (for some reason) but they cannot suddenly demand more.
Similarly, Design by Contract specifies preconditions and postconditions for each method. If that method is called, it "promises" or "guarantees" to satisfy a number of postconditions, but only provided the accompanying preconditions are met.
Let us suppose we are writing a class called Door to run automatic doors. This class defines a method called open(). Its pre/postconditions might be:
Preconditions: It is within the opening hours of the building. The alarm system is off.
Postconditions: The door is opened.
Suppose we then wish to implement a security-enabled door as a subclass of Door. The open() method for SecurityDoor would have the following new conditions:
Preconditions: The user has swiped a valid card. It is within the opening hours of the building. The alarm system is off.
Postconditions: The door is opened for ten seconds only.
This is a VIOLATION of design by contract. The subclassed method now demands more, and will only guarantee less. This violates the core principle of design by contract:
REQUIRE NO MORE, PROMISE NO LESS
This means that the SecurityDoor subclass was a bad idea. If we began using SecurityDoor objects as Door objects, we would soon violate the contract. If code was written to open all doors in case of fire, for example, the code for this would not work. Security doors would unexpectedly close after ten seconds, possibly leaving firemen trapped inside!
What seemed intuitively correct (because a Security door IS a Door) was wrong. Design by contract helps us avoid falling into such traps, much as real contracts help commerce run smoothly.
When contemplating a subclass, we must ask ourselves not whether the subclass "IS" the superclass, but whether it "SATISFIES THE CONTRACTS OF" the superclass.