The inventor of Design by Contract himself, Bertrand Meyer, notes that the contracts look formal and "shocking to most" who first encounter the concept [Meyer1997]. He adds that they are the foundation of code stability and other quality goals. The authors agree in that contracts are indeed a means to achieve those goals, where it would be hard with unit tests alone. However, contracts are not as strange to developers as they might appear at first glance. In fact, they are an implementation pattern commonly found in existing code. Assertions AgainContracts are a particular form of assertions, as explained earlier. Assertions themselves are not unknown to most developers, and they are frequently used by those more careful in large systems projects. Plain assertions are sometimes considered unnecessary in the presence of unit test suites, but they are hardly a strange and new concept. PreconditionsIn many methods, preconditions are disguised as Guard Clauses.[4] Using preconditions instead makes them easier to locate and enforces sensible rules for methods overwritten by subclasses.
PostconditionsPostconditions are often simulated by methods checking a message's result. This is commonly used when the message sent belongs to another module or is supposed to call a different application. Code like this expresses a healthy mistrust in the developers who wrote the called code. However, it should be the other code's responsibility to enforce the promises made, if only to have it in one place instead of dispersing it throughout the client code. This only works when those promises are documented, which postconditions do better than API documentation. Class InvariantsClass invariants are not frequently encountered in existing code. However, they are sometimes present without being explicitly formulated. Then, they are an annoying source of what is often called "beginners' faults." An example of this is the equals/hashCode relationship in Java.[5]
When you overwrite equals() in a class, you have to make sure that equal objects still return the same hash code. However, this is enforced nowhere, and it's stated only in the class library documentation and therefore easily missed by beginners.[6] Of course, veteran developers will always remember it, unless they are in a hurry.
Again, having explicitly stated invariants will help locate and enforce them. Developers encountering class invariants (as opposed to those writing them) will probably not find them strange and burdensome but will welcome them as an additional aid. |