Stephen Freeman Rotating Header Image

Bertrand Meyer not completely right

In this “interview with Bertrand Meyer”:http://www.artima.com/intv/contest.html on Artima, Bertrand Meyer hopes that Test-Driven Development is like Design By Contract. Well, yes and no.

Meyer has the good grace to admit he hasn’t really had time to look into TDD, but his view is that:

bq. I haven’t had the opportunity to talk to, for example, Kent Beck about this, but I hope he would agree that the right form of test-driven development is where the tests are systematic. And the best way I know to derive a systematic test is from contracts, because they’re much more general and abstract. You can derive the specific from the general. You cannot really infer the general from the specific.

First, he has the usual misunderstanding of TDD being about testing, not unreasonable given its name. But “extracting the general from the specific” is exactly what the refactoring part of TDD does, that’s how you remove duplication. The flip from Design as a Process of Invention, to Design as a Process of Discovery takes a little while to get used to but it’s liberating. It puts an end to the “deer in the headlights” experience where there are just too many unknowns to make the next (binding) decision so you find yourself incapable of deciding anything.

There’s another, more interesting, discussion that I think is worth having with the Design By Contract community. One of the important experiences of TDD is that you can control the scope of the code by adding and removing individual tests. You can slice and dice functionality and it’s easy to understand. Contract specifications tend to be harder to manipulate that way because they describe general properties — that’s the whole point. I have a suspicion that this is just a matter of style, but it’s not how DbC people see things. Like Prof Meyer, I haven’t had these discussions with the right people either (so that makes us even?), but it would be entertaining to find out.

6 Comments

  1. Dafydd Rees says:

    It seems as though Bertrand Meyer is encouraging people to see test-driven development as a “poor man’s formal methods”. I have a formal methods background, and I’ve transitioned to XP. As soon as I joined a real XP team, the first thing the coach taught me was to stop worrying about all possible cases and failure modes and only write the test I need right now.

    I hope Bertrand Meyer makes it clear that his idea of how to use TDD isn’t the norm in Extreme Programming.

  2. Steve Freeman says:

    It’s nice to hear a comment from someone who’s done formal methods properly. I think there’s some overlap which we’ll find one day, and it’s good to have done some to get the mental discipline.

    Meyer was pretty good about being clear that he needed to look into it more.

  3. Gerke Geurts says:

    There definitely is some common ground between DBC and TDD.

    The writing of tests before writing the code to make the test work compares to writing a DBC contract (essentially a class/component invariant + interface method pre- & postconditions). You explore the functionality that has to be exposed by an interface before coding its implementation. The difference is indeed that tests cover specific cases and contracts the general one.

    In practice I find I use both approaches concurrently when developing code. I first define the public interface that will provide me with some functionality. I then write some tests for the interface and subsequently write the code to pass the tests. While writing the code I add asserts in the code to document any assumption I put in the code (about input parameters, outcomes of calls to other classes/components/services). Essentially these asserts state in a general way tests that must be passed for the code to function as intended, i.e. a rough contract in the sense of DBC. And when I add an assert for a case I have not written a test for, I add a test to the test suite.

    One reason I can think of why TDD is more popular than DBC is that proper DBC requires language constructs to define constraints like invariants, preconditions and postconditions. Asserts go some way, but it is not (easily) achievable to implement all DBC rules with asserts (e.g. precondition of overiding method may never violate precondition of the overridden method). Languages like Eiffel or ASML (from Microsoft research) provide these constructs and the compiler can automatically check for run-time constraint violations. The combination of method signatures and the constraints provides very accurate and reasonably readable technical documentation as well.

  4. Steve Freeman says:

    > I first define the public interface that will provide me with some functionality.

    This is where we differ. We tend to discover the interface in writing the tests for the interface’s client.

    I always had hopes for extended static checking, there were some interesting research systems, but I’m not sure what the state of the art is now.

    I’m curious about the widespread use of internal assertions. Does it get in the way of refactoring?

  5. Hi Steve,

    > I’m curious about the widespread use of internal assertions. Does it get in the way of refactoring?

    On a system I worked on we experimented with widespread checks of class invariance and pre/post conditions. We did not find that these checks got in the way of refactoring. However, we did find that the checks caught a class of problems unit testing didn’t – the abuse of the API (or violations of the contract) 🙂

    We were able to easily track down ‘bugs’ where they were really created (or entered our library), and didn’t have the usual hunt backwards through call stacks to discover who the culprit really was.

    I think it was a pretty successful experiment.

    Channing

  6. Lance Walton says:

    Hi Steve.

    The thing that I’ve always like about Meyer is that, although you may not always agree with him, you always know exactly what it is you’re disagreeing about 🙂

    It seems to me that DbC and TDD look in opposite directions:
    * the explicit preconditions of DbC allow an object to make sure that the world is treating it right. Post conditions and class invariants are internal integrity checking mechanisms. In addition, all three help to define semantics.
    * Unit tests allow us to determine that an object is behaving correctly within the context of a system (providing of course, the unit tests are representative of the system’s usage of the class under test) – TDD simply (but with deep consequences) helps us to design the class in the first place with the rather pleasant side effect of leaving us with an automated unit test suite.

    So the way I see it, DbC is about an object looking outwards (and at itself) whereas TDD is about a system looking inwards.

    Regards,

    Lance