Real programmers don't use assertions
February 2005
Yes, it's hard to believe (this is 2005!): there are still people, many in
fact, who allege that contracts are a good idea in principle but that you just
can't convince programmers to use them. You won't hear such comments in Eiffel circles --
Eiffel programmers just use Design by Contract, apparently not knowing they're
not supposed to be able to -- but they're common elsewhere.
At a recent NSF workshop on software verification in California, several
speakers, some of them quite august, repeated this canard. It's not innocuous,
because it leads directly to directing research efforts at extracting contracts
automatically from uncontracted programs. For example Michael Ernst [2]
synthesizes loop invariants and other assertions from raw program text. This is
interesting work but has obvious limitations: after all, if you look at the
uncontracted code as the source of all truth and extract the specification from
it, that specification will faithfully reflect the code as it is, bugs and all.
What's the point?
When Karine Arnout and I looked at .NET libraries to see if we could find
contracts behind the scenes (and did uncover them, many of them [1]), our
purpose was to assess a methodological conjecture: that contracts are not a
figment of our imagination but stand behind any serious library, even if the
designer wasn't conscious of them. We were surprised to see this work greeted by
comments of the style "This is great, can you now synthesize the contracts for
us automatically?". Such a view is absurd: contracts are a tool to support
programmers throughout the software lifecycle, starting with analysis and
design, where they help you define what you want and get it right. Adding them
ex post facto is like asking yourself, after you've been driving for a few
hundred miles, where you want to go.
So here is what I said at the workshop. The allegation that we can't expect
programmers to write contracts is irrelevant; it's a wrong allegation anyway;
and even if it had any degree of truth it would be easy to address.
It's irrelevant: in what engineering discipline can progress be determined by
the engineer's supposed hostility to thinking abstractly? If you want to become an
electrical or mechanical engineer and can't understand differential equations,
you won't graduate, period. Why should we be scared of asking software engineers
to express precisely the specification of their software elements? Is the
preservation of their mental comfort -- supposedly endangered if we dare ask
them to write a precondition! -- more important than the correctness of the
software they produce? Imagine the defense after the train has derailed because
of a deficiency in the braking software: "Yes, your honor, our client's Human
Resources department ruled it would be moral torture to require programmers to
understand De Morgan's laws". Would it work? And it's not like we are talking
rocket science either. Contracts are plain boolean expressions, stating
conditions, often straightforward (but potentially catastrophic if they're not
met!), on software elements. As James McKim put it, "if you can write an
if-then-else, you can write a contract". There's no excuse for not enforcing
that discipline.
The conventional wisdom is wrong anyway: almost two decades of Eiffel experience, resulting in
millions of lines of production code, confirm that it's possible for any
competent programmer to take advantage of contracts in his or her daily work.
Eiffel programmers don't use contracts to satisfy some theoretical injunction,
but simply because they see the benefits in their daily work, from specification
and design to documenting the software, getting it right, and finding any
remaining bugs quickly and efficiently. In most cases they have no particular
mathematical background; they appreciate the simplicity and usefulness of the
concepts. While software engineering pundits gravely dissert about not causing
undue pain to programmers, Eiffel developers simply take advantage, in their
daily work, of the power of contracts.
And finally: even if there were resistance to contracts, it would be easy to
address. Let's just assume for a moment that your project does include an expert
hacker, indispensable because of the low-level tricks that enable him to succeed
where no one else dare to tread, but somehow incapable of abstraction (never
recovered from "new maths" in grade school?). Actually I think he can understand
contracts like everyone else, but let's just accept he is recalcitrant and you
don't dare offend him. This doesn't mean that you should let him produce any old
code, without specs; after all even super-hackers are mortal and someone will
have to maintain those programs. The solution then is clear: shadow the star
coder with a possibly less glamorous but more abstraction-pronecolleague; let's
call her the "contracter" (with an "e"). As the contract-averse coder happily
hacks away at his keyboard, the contracter writes the contracts, explaining to
him all along what he is really doing. Perhaps that's what "pair programming"
should be: one produces, the other abstracts. Behind every programmer there's
already, these days, one or two testers to look for errors; why not a contracter
to ensure that the errors don't get there in the first place?
In more normal circumstances, however, you don't need any of this. You don't
have to preach contracts to developers, let alone impose contracts. You just
show them the tools, and they will quickly understand all the benefits they can
derive. It doesn't take much more than one case of a potentially tricky bug,
caught trivially at test time through an invariant violation and saving hours or
days of debugging, to get hooked.
-- Bertrand Meyer
References
-----------
[1] Karine Arnout and Bertrand Meyer: "Spotting Hidden Contracts: The .NET
example", in Computer (IEEE), vol. 36, no. 11, November 2003, pages 48-55,
available at
http://www.inf.ethz.ch/personal/meyer/publications/computer/contract_extraction_published.pdf
Longer version: "Finding Implicit Contracts in .NET Components", in Proceedings
of FMCO 2002 (Formal Methods for Components and Objects), Leiden, The
Netherlands, 5-8 November 2002, LNCS 2852, Springer-Verlag, Eds. Frank de Boer,
Marcello Bonsangue, Susanne Graf, Willem-Paul de Roever, November 2003;
available at
http://www.inf.ethz.ch/personal/meyer/publications/extraction/extraction.pdf
.
[2] Michael D. Ernst, Jake Cockrell, William G. Griswold, and David Notkin:
"Dynamically discovering likely program invariants to support program
evolution", in IEEE Transactions on Software Engineering, vol. 27, no. 2, Feb.
2001, pp. 1-25.
|