Working with state
There’s no denying that immutability can provide lots of benefits in terms of testing, reducing complexity and lowering coupling. Having a language/paradigm that embraces it could be a huge productivity booster.
Unfortunately that’s not always the case or our choice to make ;).
For methods that are immutable specifying the Pre and Post condition is usually enough. However, is quite common in OOP to call methods that not only use the state of the instance but also modify it.
Using interfaces in order to talk about Pre and Post was sufficient because we were describing only the behavior of the method, not implementation. In contrast exploring the state of an instance of a class implies looking at the implementation.
The class invariant
Lets imagine that we want to implement a sorted Collection that ensures every time I iterate through the collection all the elements will be return by the default order. This time the method will modify the state.
1 2 3 4 5 6 7
Lets focus on the Add method. The test looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
The failing test is the first part of following TDD and we used the Pre and Post to help us to write it without leaving any scenario out.
Now, in order to write the implementation of the method, lets think about how are we going to keep the elements sorted.
We could use an array to store the values and keep it sorted. How can we specify this?
Similar to having a predicate to describe what happens before and after calling a method we are going to use another predicate to describe a condition that a class has to satisfy for every instance.
This condition is called class invariant (invariant in the sense that does not change) and will enforce a restriction over the implementation of a class.
Considering the case above I want to enforce that my array is always sorted.
1 2 3 4 5
The class invariant has to be satisfied (evaluated to true) before and after each method is called. It is ok if the predicate is false inside the method but we need to work to restore it.
When implementing the Add method we have no choice but to add it to the array and sort it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Is that the only implementation possible? Why not sort the elements when I need an enumerator? Something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
It is true, that should pass the test too. However, if we change the implementation then the code will break the invariant. The class invariant “guided” me to choose the implementation.
As an exercise, think about what would be the invariant in that case.
Finding the invariant helps us to discover the implementation and make sure that our methods are not only valid from the interface point of view but also sound in terms of the internal structure.
If finding pre and post is a hard task (the hardest part of TDD) finding the invariant is even harder. I’m not saying this to discourage you (after reading all the post? C’mon!). Quite the opposite.
Sometimes when writing a test (and later the implementation) we are not sure where to start. We may spend quite a bit of time looking at the test code or a class code with the feeling that something’s wrong, and not sure why.
Having the practice of finding Pre, Post and Invariant in your tool belt can help you identify the reason, simplify your task and assist you to find unwanted complexity and code smells right away.
And if it doesn’t work, clearly is time to go home and have a beer. Either way, you win.