This blog post is a continuation of the comparison and differentiation between DbC and TDD. Please take a look at part 1 which covers the design aspect (and shortly specification again which has been discussed in more detail here). Today’s post takes a look at documentation and code coupling and shows commonalities and differences of TDD and DbC towards these aspects.
One important thing for other developers to understand your code is documentation. Code comments are a first necessity here to basically explain what a code component is intended to do. But comments have the unpleasant habit to run out-of-sync with the real code if you are not carefully and consequently adapting them. Most of all if you write obligations or benefits into comments there will be no check if those requirements hold or if the real implementation matches them.
DbC with its contracts is a much better way to document those specification aspects. Contracts are coupled to the code and e.g. with Code Contracts you get static and runtime checking for them. This checked documentation makes DbC really powerful (if properly used) and avoids the asynchronicity between code and documentation. It shows developers how a component should be used, what requirements the client has to fulfill and what he can expect in return. The client can rely on these specified qualities which improves the reusability of contracted code components. Furthermore there are possibilities to integrate Code Contracts into the Sandcastle documentation and for Visual Studio 2010 there will be an add-in that immediately shows defined contracts on a component as you develop against it. With that you get great MSDN-like documentation that contains the defined contracts as well as support for your development process when you use contracted code.
Tests in terms of TDD add another aspect of documentation. Due to their exemplary nature and their specification of an element’s behavior those tests are great to show a developer the intent of a code component and give him a guideline to its usage. Since tests can be run and validated in a reproducible way developers are able to rely on defined behaviors as well.
Together with documentation comes the aspect of intention revealing. And both TDD and DbC add some value here. Both express the developer’s intention with a certain component and show far beyond code comments and naming conventions what behavior a client can expect. Developers can use the component in these specified ways and don’t have to manually investigate the component’s implementation.
One drawback of TDD is the locational gap between the code implementation and the tests as specification and documentation source. For sure this has an advantage as well: the code logic isn’t polluted with the specification and thus it’s kept clean. But the disadvantages weigh heavier for me. If developers want to show how a component behaves they have to cross the gap and investigate the tests. This is difficult for developers who are not very familiar with TDD. Furthermore tests don’t give any support for client usage of a component. Of course they give usage examples, but developers can use and especially misuse a component in arbitrary ways. This can lead to serious problems (e.g. inconsistent states) if there are no other mechanisms to prohibit misusage.
DbC on the other side sets contracts directly on the implementation of a code component in place. Thus they have a declarative nature and extend the definition of a code component. Some realizations of DbC like Code Contracts in .NET have drawbacks since they set contracts imperatively into the code, but rewrite the code after compilation to set the contracts in the „right“ places. Thus Code Contracts break the uniformity principle (different semantics should be expressed through different syntax) and pollute the code logic in some way. Other realizations like the Eiffel language have contracts as keywords built into the language which makes a better choice in my opinion. Anyway contracts at the same place as the implementation avoids the drawbacks of a locational gap. And moreover DbC prevents misusage of a component. Contracts are dynamically checked at runtime or statically at compile time and fail early if requirements are not satisfied. That’s a very important concept because it expresses a clear behavior if something goes wrong (existence of a bug) and gives a clear contract for obligations and benefits that hold and are checked in client/supplier communication.