- Designing pre-conditions, post-conditions, and invariants
- Understanding the differences between contracts and validation
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 subroutines (or classes) in a complex flow of information: that is, the results of one class are passed to the next class, whose results are again passed to the next class, and so on. As usual, the data comes from different sources, such as databases, external web services, and users. At some point in the routine, the class TaxCalculator
(which handles calculating a specific tax) is called. From the requirements of this class, the calculation only makes sense for positive numbers.
We need to think about how we want to model such a restriction. I see three options when facing such a restriction:
- Ensure that classes never call other classes with invalid inputs. In our example, any other classes called
TaxCalculator
will ensure that they will never pass a negative number. While this simplifies the code of the class under development, since it does not need to deal with the special cases, it adds complexity to the caller classes that need to be sure they never make a bad call. - Program in a more defensive manner, ensuring that if an invalid input happens, the system halts and returns an error message to the user. This adds a little complexity to every class in the system, as they all have to know how to handle invalid inputs. At the same time, it makes the system more resilient. However, coding defensively in an ad hoc manner is not productive. You may end up adding unnecessary code, such as restrictions that were already checked.
- My favorite approach, and the goal is to define clear contracts for each class we develop. These contracts clearly establish what the class requires as pre-conditions, what the class provides as post-conditions, and what invariants always hold for the class. This is a major modeling activity for which the design-by-contract idea will inspire us (originally proposed by Bertrand Meyer).
Such contract decisions happen while the developer is implementing the functionality. That is why design-by-contract appears on the “testing to guide development” side of the development flow I propose (see figure 1.4).
Leave a Reply