Bertrand Meyer is a software pioneer whose activities have spanned both the academic and business worlds. He is currently the Chair of Software Engineering at ETH, the Swiss Institute of Technology. He is the author of numerous papers and many books, including the classic Object-Oriented Software Construction (Prentice Hall, 1994, 2000). In 1985, he founded Interactive Software Engineering, Inc., now called Eiffel Software, Inc., a company which offers Eiffel-based software tools, training, and consulting.
On September 28, 2003, Bill Venners conducted a phone interview with Bertrand Meyer. In this interview, which is being published in multiple installments on Artima.com, Meyer gives insights into many software-related topics, including quality, complexity, design by contract, and test-driven development.
Bill Venners: When I was reading your book, Object-Oriented Software Construction in preparation for this interview, I found that many of the claims you made about Design by Contract reminded me of claims made about test-driven development. You wrote that Design by Contract "helps us build software in which reliability is built in rather than achieved after the fact through debugging." You also wrote, "We will derive tremendous benefits from writing the assertions at the same time as we write the software, or indeed before we write the software." And, "With hardly any extra effort, you get software that works the first time around." How does Design by Contract achieve this, and how is Design by Contract the same or different from test-driven development?
Bertrand Meyer: A test checks one case. A contract describes the abstract specification for all cases. Test-driven development is an interesting idea, but I think the way to go is to derive the tests from the contracts.
I think there are two kinds of people interested in test-driven development. First, there are people who are very happy not to have to write a specification. If that's what you hope to get from Extreme Programming (XP), I don't think you'll get much improvement. But then there are people who are more seriously applying the idea of test-driven development, the way at least I would consider applying it, where the tests are really systematic. 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.
Bill Venners: What do you mean by systematic?
Bertrand Meyer: It was shown many years ago through a very simple argument that there's no such thing as an exhaustive test, a test that exercises all possible cases. So we know we can't have an exhaustive test, but we can have systematic tests that have a likelihood of exercising the cases that will fail. For example, if you have a parameter that must be between certain bounds, then you want to test the values close to bounds of the range. You want to test maybe the value in the middle, and maybe a few in-between. So we want to have tests that are systematic in that sense, and contracts help a lot generating such "systematic" tests.
Bill Venners: Test-driven development seems to require less formal thought than Design by Contract. In Design by Contract, you ponder about the abstract contract of types. In test-driven development, you think about one small task at a time. Write a test, implement the code, refactor, and repeat. In Design by Contract, you design at the level of types. In test-driven development, you design in smaller pieces, each step building on the previous. The design of an entire type emerges from this iterative test-code-refactor process.
To what extent are formal contracts required for successful software projects? You suggested that people who are attracted to test-driven development because they don't want to write specifications won't go as far. Why not? How does being formal about specifying contracts, which takes more time and effort up front, help you go farther?
Bertrand Meyer: The word "formal" is scary to many people, so we shouldn't overplay the formality of Design by Contract. Many contract elements are just relatively simple affairs, such as
x is positive, or this particular pointer is not
null. This kind of statement accounts for the majority of contract elements. More complicated elements tend to be expressed by Boolean expressions that include function calls. You might declare that a particular property, such as that the account is not delinquent, will hold for a bank account, and that property is expressed by a certain function in the class.
People are doing really formal development, and that's a very interesting area as well, but it's probably beyond what most developers are willing to contemplate. One of the things people find attractive in the Design by Contract approach as embodied in Eiffel is that it does not really require extensive training or a major departure from accepted practices. James McKim who is the coauthor with Richard Mitchell of the book Design by Contract by Example, likes to say, "If you can write a conditional expression—if you can write an if statement—then you can write a contract." And he's absolutely correct. There's nothing magical or difficult in contracts. You don't need a PhD in formal logic.
The issue is not so much adopting a completely formal approach to software development. There are people promoting this, and it's a field in which I'm interested in the more academic side of my activities, but it's really not what Design by Contract is about. Design by Contract in very simple terms is stating what you expect and what you guarantee in precise terms in the same way you express what you do.
Bill Venners: By "formal," I simply mean thinking at a more abstract level. When you are writing a unit test for a small incremental piece of functionality, you don't necessarily need to step back and consider the interface of the entire type. In fact, my understanding is that you are supposed to take small steps so that your mind can just focus on adding one small piece of functionality at a time, allowing the larger overall design to emerge out of your many small local decisions.
Bertrand Meyer: This is where I keep wondering whether I have a disagreement or not with the XP crowd. Maybe I do and maybe I don't. It is risky to judge an approach on the basis of how people apply it. It is clear that there are people who have seized on the XP ideas as an excuse not to abstract very much. They may be wrong. They may just be misapplying the XP idea. Here I really don't know. I'd like to have a more extensive discussion with people like Kent Beck and Martin Fowler.
But that being said, if you don't want to abstract, you are really going to be in trouble. Tests are a way to find errors. You may have removed enough errors that your tests pass, and therefore you think you're OK. But if you don't want to abstract more into the general case, then you are really in trouble. This is where the professional responsibility aspect of our work comes in. Many of the major catastrophes of the history of software were caused by stupid details, extreme cases that should not have occurred. These cases were ignored during development and testing because no one thought of them, because they were so baroque, so unlikely, or outside of the box. This is the kind of thing that really often plagues systems: the list that happened to be tested only when it was not empty. But once in a while the list is empty and everything crashes.
You need to abstract a little bit and ask yourself, "What do I expect of this particular data structure? Is it OK if the list is empty, or is it an erroneous case? If it's an erroneous case, whose responsibility is it to make sure the list is not empty?" If you don't do this abstraction, which doesn't require a PhD in mathematics but does require care and generalization, then you're not really fulfilling your duty even if all your tests have passed with flying colors.
Come back Monday, March 8 for the final installment of this conversation with Eiffel creator Bertrand Meyer. If you'd like to receive a brief weekly email announcing new articles at Artima.com, please subscribe to the Artima Newsletter.
Bertrand Meyer is the author of Object-Oriented Software Construction, which is available on Amazon.com at:
Bertrand Meyer's Home Page at ETH, the Swiss Institute of Technology:
The Grand Challenge of Trusted Components, presented by Bertrand Meyer at the International Conference on Software Engineering, May 2003:
The Structure and Interpretation of Computer Programs, by Harold Abelson and Gerald Jay Sussman with Julie Sussman:
Find out more about Eiffel at:
The Eiffel language FAQ:
The 2001 Interview with Programming Expert Bertrand Meyer in InformIT:
(Gratuitously long URL omitted...)
Design by Contract by Example, by Richard Mitchell and Jim McKim:
Have an opinion? Readers have already posted 22 comments about this article. Why not add yours?
Bill Venners is president of Artima Software, Inc. and editor-in-chief of Artima.com. He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Bill has been active in the Jini Community since its inception. He led the Jini Community's ServiceUI project that produced the ServiceUI API. The ServiceUI became the de facto standard way to associate user interfaces to Jini services, and was the first Jini community standard approved via the Jini Decision Process. Bill also serves as an elected member of the Jini Community's initial Technical Oversight Committee (TOC), and in this role helped to define the governance process for the community. He currently devotes most of his energy to building Artima.com into an ever more useful resource for developers.
Artima provides consulting and training services to help you make the most of Scala, reactive and functional programming, enterprise systems, big data, and testing.