Design by Contract lecture notes

These notes assume the students have read Fun with DBC.

Key Points

Diagram of scope of contracts.

Design By Contract implies:
  1. Developers clearly document the contracts in their public interfaces (e.g., with javadocs).
  2. Developers trust that other team members will adhere to the contract and don't write error checking code. (This idea can be quite difficult to sell; many developers have a mistaken, paranoid, "bullet-proofing" mentality.)
  3. The team must decide how to handle broken contracts both during development and during deployment.

The key benefits

Comparison: DBC versus Error-checking 


Error Checking
Design By Contract
During
Development

The method checks (used) data members and its parameters.
In case of an error, the method triggers an exception or returns an error.
The designer writes strong preconditions against data members and input parameters.
Code to check the preconditions may be:
  1. Omitted entirely; the team believes good programmers and code inspections are sufficient.
  2. Written as asserts (e.g. Java 1.4 Assert)
  3. Included by the language compiler (e.g. Eiffel)
  4. Included by an assertion-checking compiler (e.g., JML)
But the programmer never, under any circumstance, writes code to check data members and parameters. NEVER!
During
Deployment

The method code runs as written by the programmer.
Product quality code must handle any "conceivable" error.
If there is no run-time error checking code, the method runs with defects in its input; results are indeterminate. The method may work correctly or produce a defect or crash the program or ??

If there is run-time error checking code, that code does something appropriate. It must be possible to disable the run-time code; this may be done at build-time or by the user depending on circumstances.
The code might:
  1. Inform the user. (what should the user be told?)
  2. Gracefully crash the program (Blue screen, flashing light, ???)
  3. Attempt a fix.
Notes
In both styles, error-checking code must be written for errors caused by the operating environment.
A long discussion on "conceivable" is required for all software projects.
Meyer defines 3 possible outcomes in an Eiffel rescue clause.
  1. Retry
  2. Organized panic (cleanup and throw exception)
  3. False alarm


Example: Square Root

double sqrt (double x) (design by contract spec)
double sqrt (double x) (unix error checking spec)




There is a third alternative often practice by inexperienced teams.  They don't do error checking, but they don't document their preconditions (usually because they haven't thought about them).  Obviously this is the worst of both worlds.  In Mr. Dalbey's course your team must decide which strategy to adopt and document method headers accordingly.



Here are some poor Precondition examples, given the method signature:

addClavitz (Clavitz c)

Precondition:  c != null         (not necessary: not worth the trouble)
Precondition: c is a Clavitz (redundant, given in method signature)
Precondition: c is valid (unclear: doesn't mean anything)
Precondition: c is initialized (too vague)
Precondition: user entered c (user's can't be part of a contract)
Precondition: there is sufficient memory to clone c (must be a run-time error check)


Papers and other resources

Last updated on 1/15/04