Contracts in the Domain Model

This blog-post gives a brief introduction to contract-oriented programming aka design by contract in general and in relation to Groovy with gcontracts assertions. The Problem With each Grails application generation of test-cases is simply part of the game. Whenever you create a domain-class the corresponding unit-test is generated directly. With the test-first approach of Test-Driven Development (TDD) each iteration in the development process starts with the task of writing tests specifying the intended behavior of the targeted components. E.g. use-case: a customer in the coffee-house might order several cups of coffee
 
class Customer {
    def Order createOrder() { ... }
}
 
 
class Order {
    def void addItem(Item someItem)  { ... }
}
 
When executing the test-first approach we would start with writing a unit-test for class Item, going on to class Order and finally writing one for class Customer. e.g. ItemTests
 
class ItemTests  {
    @Test
    def void testCreateItem()  {
        def item = new Item(COFFEE_TYPE.Cappuccino, 1) // (type, amount)

        assertEquals COFFEE_TYPE.Cappuccino, item.coffee_type()
        assertEquals 1, item.amount()
    }
}
 
As you might have already noticed it is pretty hard to find tests that maximize the covering of business requirements. Most of the time, unit-tests are written in the first iteration, in subsequent iterations that tests are simply rewritten to "get green". Your mileage may vary, but the main problem with test-cases are that each single test-case only tests a small fraction of the input domain, that is, the cartesian product of the current function: e.g. the constructor call to new Item(COFFEE_TYPE.Cappuccino, 1) is nothing more than a function call that generates a new item object, with (COFFEE_TYPE, NUMBER) as parameters. Set theory would map that function to the following expression: Mapping a Constructor Function Meaning that the overall set of parameter tuples is mapped by the cartesian product between all COFFEE_TYPE and all INTEGER values, the result is a single tuple out of all cartesian product tuples. Just imagine the cartesian product as a set that contains all possible combinations of this function's parameter values. The unit-test tests exactly one single pair out of the cartesian product: several pairs in the cartesian productIn this simple example it gets pretty obvious that even if tests have a high code coverage, they hardly never can satisfy testing a large portion of the problem domain. That is where contracts come into play. An Introduction to Contract-Oriented Programming Contracts are the clue between the specification and the implementation of a certain software artifact, in object-oriented speak: classes. Formally, contracts are based on so-called Hoare rules which provide a formal system towards logical rules of reasoning on the correctness of computer programs [0]. The main feature of this formal system is the so-called Hoare triple: Hoare Triplewhere P and Q are assertions and C represents a set of commands. A concrete Hoare triple states that before execution of C, the precondition P must be true, after the execution the postcondition Q must hold. Pre- and postconditions represent so-called assertion types. In a gcontracts enabled Groovy program you might use pre- and postconditions by using either @Requires or @Ensures:
 
class Item {
    private CoffeeType coffee_type
    ...

    @Requires({ type != null && amount > 0 })
    def Item(final CoffeeType type, final Integer amount)  { ... }

    @Ensures({ old -> old.coffee_type != coffee_type })
    def void change_coffee_type_to(final CoffeeType type)  { ... }
}
 
As you can see pre- and postconditions are applied on constructors or methods only. In addition, there is the need to express assertions which must be preserved by all methods and every instance of that class; these assertion types are called class-invariants:
 
@Invariant({ coffee_type != null && amount > 0 })
class Item { ... }
 
A class-invariant must be preserved after every constructor call and before/after each method call. When executing a method with a precondition P, a postcondition Q and a class-invariant C, before a method call the assertion expression P AND C and after a method call expression Q AND C must be true. When inheritance comes into play we'll have to have a separate look at all assertion types: Conclusion Pre-, postconditions and class-invariants provide a great way of minimizing the parameter domain and ease testing of your domain model. Having instrumented your code with these assertions, you can concentrate on e.g. extreme boundaries of parameter values or obscure business cases when writing your tests. Indeed, a carefully instrumented domain-model has further advantages: To be clear: if your task is to write e.g. a simple CRUD Grails application, you wont be dealing with this stuff. But, if you are dealing with complex domain models and throw moving business requirements in (what project lives without them?), you might give contract-oriented programming a try.

[0] An axiomatic basis for computer programming, C. A. R. Hoare
[1] GContracts - Contract-Oriented Programming with Groovy, Github