Recently I came across a class used to store some application configuration. The configuration was stored in an XML file which was parsed in the constructor of the class. Each method of the class started with getting the root element of the XML file and if that element did not exist it needed to be created. That was a lot of code repetition that could be extracted into a common private method. But before I started changing the code, I realized it could be done in a more elegant way.
Instead of performing the check at every method invocation, I would do it only in the constructor and ensure that no method breaks that condition. This is called a class invariant.
An invariant is a condition which is always true in any state of the object (or system). Invariants are used heavily when designing algorithms, but a lot of programmers somehow forget about them.
In my case it is pretty simple, the invariant says: “the document has the root element”. The document is loaded when the class is created and if there is no root element, one is created. No method of the class will reload the document, nor delete the root element.
Requirements for Using Invariants
Having good ecapsulation is necessary when using invariants, because you don’t want to have a method outside of your class that can break the invariant.
Invariants need to be documented, anyone who modifies your class should be aware of the invariants. So put a section of comments at the top of your class stating all the invariants.
Invariants need to be tested: put assertions at the end of each test.
As with everything there are downsides on using invariants.
When using invariants in combination with inheritance, things may get complicated. If you extend a class that preserves some invariants, first of all, you need to be aware of the invariants, and then ensure that you don’t break them. For example if you have a template method in the parent class, and you implement one of the abstract methods used by the template method, you would need to run the tests of the parent class on your subclass. You can make an invariant unbreakable by the sublcasses by declaring the relative data structures as private (as opposed to protected).
Your invariant might be too strong. On a previous project, I needed to create a file system structure (assuming it won’t be modified externally) with a lot of files that had naming conventions. There were also a lot of conditions like file A must exist, if file C exists then we need file B etc. These conditions were required in order to run a sequence of legacy tools on the files. We performed all the validation at the beginning so we were sure that you could run all the tools.
But running all the tools wasn’t always required. So instead of maintaining all the conditions as invariants, we refactored to use a minimal set of conditions as invariant, and express all the others as preconditions to running the relative tools, and verifying preconditions at the beginning of the method.
If you realize that you are maintaining too many invariants, it might be the case that you need to decompose your class into several classes. You might even end up inventing some reusable primitives (monitors, transactions, atomic bcast)