chapter four

4 Design by contracts

 

This chapter covers

  • What contracts are, how to design and ensure them
  • What pre-conditions, post-conditions, and invariants are and how to model them

Imagine a piece of software that handles a very complex financial process. For that "big routine" to happen, the software system chains calls to several sub-routines (or classes) in a complex flow of information, i.e., the results of one class are passed to the next class, so on and so forth. As usual, the data comes from different sources, such as databases, external web services, and the users themselves. At some point in the routine, the class TaxCalculator which, as its name says, handles the calculation of a specific tax, is called. From the requirements of this class, we see that the calculation only makes sense for positive numbers; a negative number would make the calculations go wild.

What we need to think about now is how we are going to model such a restriction. We know that values that come to TaxCalculator, whatever they are, must always be positive. I see three options when facing restrictions like that:

4.1 Pre-conditions and post-conditions

4.1.1 The assertion keyword

4.1.2 Strong and weak pre- and post-conditions

4.2 Invariants

4.3 Changing contracts and the Liskov Substitution Principle

4.3.1 Inheritance and contracts

4.5 Design-by-contract in the real world

4.5.1 Weak or strong pre-conditions?

4.5.2 Input validation or contracts? Or both?

4.5.3 Asserts or exceptions: when to use one and the other?

4.5.4 Exception or soft return values?

4.5.5 When not to use design-by-contract?

4.5.6 Should I write tests for my pre-conditions, post-conditions, and invariants?

4.5.7 Tooling support

4.6 Summary

4.7 References