scispace - formally typeset
Open AccessJournal ArticleDOI

Applying 'design by contract'

Bertrand Meyer
- 01 Oct 1992 - 
- Vol. 25, Iss: 10, pp 40-51
TLDR
Methodological guidelines for object-oriented software construction that improve the reliability of the resulting software systems are presented and the theory of contract design and the role of assertions in that theory are discussed.
Abstract
Methodological guidelines for object-oriented software construction that improve the reliability of the resulting software systems are presented. It is shown that the object-oriented techniques rely on the theory of design by contract, which underlies the design of the Eiffel analysis, design, and programming language and of the supporting libraries, from which a number of examples are drawn. The theory of contract design and the role of assertions in that theory are discussed. >

read more

Content maybe subject to copyright    Report

: Applying Design by
Contract
Bertrand Meyer
Interactive Software Engineering
Reliability is even more
important in object-
oriented programming
than elsewhere. This
article shows how to
reduce bugs by building
software components
on the basis of carefully
designed contracts.
40
s object-oriented techniques steadily gain ground in the world of software
development. users and prospective users of these techniques are clam-
oring more and more loudly for a
methodology of object-oriented
software construction - or at least for some methodological guidelines. This
article presents such guidelines, whose main goal is to help improve the reliability
of software systems. Reliability is here defined as the combination of correctness
and robustness or. more prosaically, as the absence of bugs.
Everyone developing software systems. or just using them, knows how pressing
this question of reliability is in the current state of software engineering. Yet the
rapidly growing literature on object-oriented analysis, design, and programming
includes remarkably few contributions on how to make object-oriented software
more reliable. This is surprising and regrettable, since at least three reasons justify
devoting particular attention to reliability in the context of object-oriented devel-
opment:
l
The cornerstone of object-oriented technology is reuse. For reusable compo-
nents, which may be used in thousands of different applications, the potential
consequences of incorrect behavior are even more serious than for application-
specific developments.
l
Proponents of object-oriented methods make strong claims about their bene-
ficial effect on software quality. Reliabi!ity is certainly a central component of
any reasonable definition of quality as applied to software.
*The object-oriented approach, based on the theory of abstract data types,
provides a particularly appropriate framework for discussing and enforcing
reliability.
The pragmatic techniques presented in this article, while certainly not providing
infallible ways to guarantee reliability, may help considerably toward this goal.
They rely on the theory of design by contract. which underlies the design of the
Eiffel analysis, design, and programming language and of the supporting libraries,
from which a number of examples will be drawn.
The contributions of the work reported below include
l
a coherent set of nwthodological principles helping to produce correct and
robust software;
l
a systematic approach to the delicate problem of how to deal with abnormal
cases. leading to a simple and powerful exception-handling mechanism; and

*a better understanding of inherit-
ance and of the associated techniques
(redeclaration, polymorphism, and
dynamic binding) through the no-
tion of subcontract, allowing a sys-
tematic approach to using these pow-
erful but sometimes dangerous
mechanisms.
Most of the concepts presented here
have appeared elsewhere. They were
previewed in the book Object-Oriented
Software Construction; and a more com-
plete exposition was presented in a re-
cent book chapter, from which this ar-
ticle has been adapted. More profoundly,
this work finds its root in earlier work
on systematic program development.i
and abstract data types. h-X This article
focuses on the central ideas, introduc-
ing them concisely for direct applica-
tion by developers.
Defensive programming
revisited
Software engineering and program-
ming methodology textbooks that dis-
cuss reliability often emphasize the tech-
nique known as defensive programming,
which directs developers to protect ev-
ery software module against the slings
and arrows of outrageous fortune. In
particular, this encourages programmers
to include as many checks as possible,
even if they are redundant with checks
made by callers. Include them anyway,
the advice goes; if they do not help. at
least they will not harm.
This approach suggests that routines
should be as general as possible. A par-
tial routine (one that works only if the
caller ensures certain restrictive condi-
tions at the time of the call) is consid-
ered dangerous because it might pro-
duce unwanted consequences if a caller
does not abide by the rules.
This technique, however, often de-
feats its own purposes. Adding possibly
redundant code just in case only con-
tributes to the softwares complexity -
the single worst obstacle to software
quality in general. and to reliability in
particular. The result of such blind check-
ing is simply to introduce more soft-
ware. hence more sources of things that
could go wrong at execution time, hence
the need for more checks, and so on ad
infinitum. Such blind and often redun-
dant checking causes much of the com-
plexity and unwieldiness that often char-
acterizes software.
Obtaining and guaranteeing reliabil-
ity requires a more systematic approach.
In particular, software elements should
be considered as implementations meant
to satisfy well-understood specifications,
not as arbitrary executable texts. This is
where the contract theory comes in.
The notion of contract
Assume you are writing some pro-
gram unit implementing a task to be
performed at runtime. Unless the task
is trivial, it involves a number of sub-
tasks. For example, it might appear as
my-task is
d0
subtask, ;
subtask? ;
subtask,, ;
end
a form that suffices for this discussion.
although in many cases the control struc-
ture linking the various subtasks is less
simple than the mere sequencing shown
here.
For each of these subtasks, you may
either write the corresponding solution
in line as part of the body of my-task, or
rely on a call to another unit. The deci-
sion is a typical design trade-off: Too
much calling causes fragmentation of
the software text: too little results in
overcomplex individual units.
Assume you decide to use a routine
call for one of the subtasks. This is sim-
ilar to the situation encountered in ev-
eryday life when you decide to contract
out for a certain (human) task rather
than doing it yourself. For example. if
you are in Paris and want an urgent
Table 1. Example contract.
letter or package delivered to another
Paris address, you may decide to deliver
it yourself, or you may contract out the
task to a courier service.
Two major properties characterize
human contracts involving two parties:
*Each party expects some benefits
from the contract and is prepared to
incur some obligations to obtain them.
*These benefits and obligations are
documented in a contract document.
Table 1 shows an imaginary roster of
obligations and benefits for the courier
service of the example.
A contract document protects both
sides:
l
It protects the client by specifying
how much should be done: The client is
entitled to receive a certain result.
l
It protects the contractor by speci-
fying how little is acceptable: The con-
tractor must not be liable for failing to
carry out tasks outside of the specified
scope.
As evidenced by this example, what is
an obligation for one party is usually a
benefit for the other.
This example also suggests a some-
what more subtle observation, which is
important in the following discussion
(and in studying the application of these
ideas to concurrent computation). If the
contract is exhaustive, every obliga-
tion entry also in a certain sense de-
scribes a benefit by stating that the
constraints given are the only relevant
ones. For example, the obligation entry
for the client indicates that a client who
satisfies all the constraints listed is enti-
tled to the benefits shown in the next
entry. This is the No Hidden Clauses
rule: With a fully spelled out contract
between honest parties, no requirement
Party
Obligations
Benefits
Client Provide letter or package of no Get package delivered to
more than 5 kgs. each dimension
recipient in four hours or
no more than 2 meters. less.
Pay 100 francs.
Supplier
Deliver package to recipient
in four hours or less.
No need to deal with
deliveries too big, too
heavy, or unpaid.
October 1992
41

other than the contracts offi-
cial obligations may be im-
posed on the client as acondi-
tion for obtaining the
contracts official benefits.
The No Hidden Clauses
principle does not prevent us
from including references.
implicit or explicit, to rules
not physically part of the con-
routine-name (argument declarations) is
-- Header comment
require
Precondition
do
Routine body, ie. instructions
eusare
Postcondition
end
tract. For example, general
Figure 1. A routine equipped with assertions.
rules such as the relevant laws
and common business prac-
tices are implicitly considered
to be part of every contract of
a certain kind. even if not ex-
plicitly repeated in the text of
each contract. They apply to
both client and supplier and
will lead below to the notion
of class invariant.
put-child (new: NODE) is
--
Add new to the children of current node
require
new /= Void
do
. . .
Insertion algorithm . . .
ensure
new.parent = Current;
child-count =
old
child-count + 1
end
-- put-child
Assertions:
This is the contract en-
forced by put-child on any
potential caller. It contains
the most important informa-
tion that can be given about
the routine: what each party
in the contract must guaran-
tee for a correct call, and what
each party is entitled to in
return. Because this informa-
tion is so crucial to the con-
struction of reliable systems
using such routines, it should
be a formal part of the rou-
tines text (see Figure 2).
A few more details about
the rules of object-oriented
programming as embodied in
Eiffel should help make this
example completely clear:
l
A reference such as new
is either void (not attached
to any object) or attached to
Contracting for
Figure 2. Assertions for child insertion routine.
software -
It is not difficult to see how the pre-
ceding ideas apply to software construc-
tion. If the execution of a certain task
relies on a routine call to handle one of
its subtasks, it is necessary to specify the
relationship between the client (the call-
er) and the supplier (the called routine)
as precisely as possible. The mecha-
nisms for expressing such conditions
are called assertions. Some assertions.
called preconditions and postconditions.
apply to individual routines. Others, the
class invariants, constrain all the rou-
tines of a given class and will be dis-
cussed later.
It is important to include the precon-
ditions and postconditions as part of
routine declarations (see Figure 1).
In this Eiffel notation, the Require
and Ensure clauses (as well as the head-
er comment) are optional. They intro-
duce assertions-respectively the pre-
condition and the postcondition. Each
Table 2. The put-child contract.
assertion is a list of Boolean expres-
sions, separated by semicolons: here a
semicolon is equivalent to a Boolean
and but allows individual identifica-
tion of the assertion clauses.
The precondition expresses require-
ments that any call must satisfy if it is to
be correct; the postcondition expresses
properties that are ensured in return by
the execution of the call.
A missing precondition clause is equiv-
alent to the clause Require True, and a
missing postcondition to the clause En-
sure True. The assertion True is the
least committing of all possible asser-
tions. Any possible state of the compu-
tation will satisfy it.
Consider, for example. in a class TREE
describing tree nodes. a routineput-child
for adding a new child to a tree node
Currmr. The child is accessible through
a reference, which must be attached to
an existing node object. Table 2 infor-
mally expresses the contract.
an object: In the first case, it
equals the value Void. Here
the precondition expresses
that the reference new must not be void,
as stated informally by the correspond-
ing entry in Table 2.
l
In accordance with Eiffels object-
oriented principles, the routine will ap-
pear in the text of a class describing
trees, or tree nodes. This is why it does
not need an argument representing the
node to which the routine will add the
reference new as a child; all routines of
the class are relative to a typical tree
node. the current instance of the class.
In a specific call such as some-
node.put-child (x), the value before the
period, here
some-node,
serves as the
current instance.
*In the text of the class, the pre-
defined name Current serves, if neces-
sary, to refer to the current instance.
Here it is used in the postcondition.
*The notation Old child-count, ap-
pearing in the postcondition ofput-child,
denotes the value of child-count as cap-
tured on entry to a particular call. In
Party
Client
Supplier
Obligations
Use as argument a reference, say new. to an
existing node object.
Insert new node as required.
Benefits
Get updated tree where the Current node has
one more child than before; new now has
Current as its parent.
No need to do anything if the argument is not
attached to an object.
42
COMPUTER

other words, the second clause of
though practically significant,
the postcondition expresses that
comes only after achieving that
the routine must increase
child-countby
one. The construct
Another way of expressing this
Old may appear only in a routine
postcondition.
~~ more fundamental goal.
observation is to notice that as-
sertions do not describe special
Figure 3. Handling a special case.
but expected cases that call for
The role of
special treatment. In other words,
the above assertions are not a
assertions
assertions are monitored at runtime,
way to describe (for example) the han-
depending on programmer wishes. But
dling of void arguments to
put-child.
If
this is not a crucial question at this point. we wanted to treat void arguments as an
You may well be wondering what The prime goal of this discussion is to acceptable (although special) case, we
happens if one of these conditions fails find ways of writing reliable software ~
would handle it not through assertions
to be satisfied during execution. This systems that work. The question of what
but through standard conditional con-
question will be answered by whether happens when they do
not
work, al- trol structures (see Figure 3).
Further sources
One of the two primary sources of inspiration for this work
is the research on program proving and systematic program
construction pioneered by Floyd, Hoare, and Dijkstra.3
Other well-known work on the application of proof methods
to software construction includes contributions by Gries
and Mills.5 The other major influence is the theory of ab-
stract data types (see references in the body of the article).
The use of assertions in an object-oriented language and
the approach to inheritance presented here (based on the
notion of subcontracting) appear original to Eiffel. The ex-
ception-handling model and its implementation are also
among Eiffels contributions. These mechanisms, and the
reasoning that led to them, are discussed in detail in refer-
ences 1 and 2 of the main bibliography at the end of the ar-
ticle.
The rescue clause notion was actually derived from a cor-
responding formal notion of surrogate function, also called
doppelgtinger, which appeared in the specification method
and language M,s a direct successor to Abriafs origin&l 2
Ianguage.*4 Like 2 and unlike Eiffel, M was a formal specffi-
cation language, not an executable language. Functions in
an M specification may be partial. A surrogate is associated
with a partial function and serves as a backup for arguments
that do not belong to that functions domain.
References
The notion of class invariant comes directly from Hoares
data invariants. Invariants, as well as other assertions, also
play an important role in the VDM software specification
method, as described by Jones.7 The transposition of data
invariants to object-oriented software development, in the
form of class invariants, appears to be new with Eiffel.
1. R.W. Floyd, Assigning Meanings to Programs, Pmt. Am. Math.
Sot. Symp. in Applied Math., Vol. 19, J.T. Schwartz, ed.. American
Mathematical Society, Providence, RI., 1967, pp. 19-31.
2. C.A.R. Hoare, An Axiomatic Basis for Computer Programming,
Comm. ACM, Vol. 12, No. 10, Oct. 1969, pp. 576-660, 663.
3. E.W. Dijkstra, A Discipline of Programming, Prentice Hall, Engle-
wood Cliffs, N.J., 1976.
Nonobject-oriented research languages that support as-
sertions have included Euclid8 and Alphards; see also the
Ada-based specification language Anna.O CLU, cited in the
text, includes nonformal assertions.
4. D. Gries. The Science of Programming, Springer-Vertag, Berlin
and New York, 1961.
5. H.D. Mills et al., Principles of Computer Prvgramming: A Maths
maksl Approach, Allyn and Bacon, Boston, 1987.
The view of programs as mechanisms to compute partial
functions is central in the mentioned VDM method.
6. CAR. Hoare, Proof of Correctness of Data Representations,
Acta Infonnatica, Vol. 1, No. 4, 1972, pp. 271-261.
Another view of exceptions can be found in Cristian.
Eiffels notion of a rescue clause bears some resemblance
to Randells recovery blocks,1z but the spirit and aims are
different. Recovery blocks as defined by Randell are alter-
nate implementations of the original goal of a routine, to be
used when the initial implementation fails to achieve this
goal. In contrast, a rescue clause does not attempt to carry
on the routines official business; it simply patches things up
by bringing the object to a stable state. Any retry attempt
uses the original implementation again. Also, recovery
blocks require that the initial system state be restored be-
fore an alternate implementation is tried after a failure. This
appears impossible to implement in any practical environ-
ment for which efficiency is of any concern. Eiffels rescue
clauses do not require any such preservation of the state;
the only rule is that the rescue clause must restore the
class invariant and, if resumption is attempted, the routine
7. C.B. Jones, Systematic Sofhvare Development Using VDM, Pren-
tice Hall, Englewood Cliis, N.J., 1966.
6. B.W. Lampson et al., Report on the Programming Language Eu-
clid, SlGPlan Notices, Vol. 12, No. 2, Feb. 1977, pp. l-79.
9. Mary Shaw et al., Alphard: form and Content, Springer-Veriag,
Berlin and New York, 1961.
IO. D. Luckham and F.W. von Henke, An Overview of Anna, a Speci-
fication Language for Ada, /EEE Software, Vol. 2, No. 2, Mar.
1965, pp. 9-22.
11. F. Cristian, Y)n Exceptions, Failures, and Errors, Technology and
Science of lnformetics, Vol. 4, No. 4, July-Aug. 1985.
12. B. Randell, System Structure for Software Fault Tolerance, /E/X
Trans. Software Eng., Vol. SE-I, No. 2, June 1975, pp. 220-232.
13. 8. Meyer, M: A System Description Method, Tech. Repot?
TRCS65-15. Computer Science Dept., Univ. of California, Santa
Barbara, 1966.
precondition.
14. J.-R. Abrial, S.A. Schuman, and B. Meyer, A Specification Lan-
_-
guage,in
On the Construction of Programs, R. McNaughten and
R.C. McKeag, eds., Cambridge University Press, England, 1960.

Assertions (here the pre-
condition) are something else:
ways to describe the condi-
tions on which software ele-
ments will work, and the con-
invariant
ular the design of the librar-
ies, suggests that the system-
left /= Void ierpriss (lefiqareni = Curreni);
right I= Void int@ies (righyareni = Current)
atic use of a demanding style
can be quite successful. In this
. approach, every routine con-
ditions they will achieve in Figure 4. An invariant for binary trees.
- return. By putting the condi-
tion rrew /=
Void
in the pre-
condition, we make it part of the rou-
tines specification; the last form shown
(with the If) would mean that we have
changed that specification, broadening
it to include the special case
new = Void
as acceptable.
As a consequence. any runtime viola-
tion of an assertion is not a special case
but always the manifestation of a soft-
ware bug. To be precise:
checking blindly, as with defensive pro-
gramming, you can use clearly defined
contracts that assign the responsibility
for each consistency condition to one of
the parties. If the contract is precise and
explicit, there is no need for redundant
checks.
centrates on doing a well-de-
fined job so as to do it well,
rather than attempting to
handle every imaginable case. Client
programmers do not expect miracles.
As long as the conditions on the use of
a routine make sense, and the routines
documentation states these conditions
(the contract) explicitly, the program-
mers will be able to use the routine
properly by observing their part of the
deal.
l
A precondition violation indicates
a bug in the client (caller). The caller
did not observe the conditions imposed
on correct calls.
One objection to this style is that it
seems to force every client to make the
same checks, corresponding to the pre-
condition, and thus results in unneces-
sary and damaging repetitions. But this
argument is not justified:
l
A postcondition violation is a bug in
the supplier (routine). The routine failed
to deliver on its promises.
The stronger the precondition, the
heavier the burden on the client. and
the easier for the supplier. The matter
of who should deal with abnormal val-
ues is essentially a pragmatic decision
about division of labor: The best solu-
tion is the one that achieves the simplest
architecture. If every routine and caller
checked for every possible call error,
routines would never perform any use-
ful work.
In Table 2, the bottom-right entry is
particularly noteworthy. If the precon-
dition is not satisfied, the routine is not
bound to do anything, like a mail deliv-
ery company given a parcel that does
not meet the specification. This means
that the routine body should
not
be of
the form mentioned above:
In many existing programs, one can
hardly find the islands of useful pro-
cessing in oceans of error-checking code.
In the absence of assertions, defensive
programming may be the only reason-
able approach. But with techniques for
defining precisely each partys respon-
sibility, as provided by assertions, such
redundancy (so harmful to the consis-
tency and simplicity of the structure) is
not needed.
l
The presence of a preconditionp in
a routine r does not necessarily mean
that every call must test for
p,
as in
Observations on
software contracts
if
x.p
then
x.r
else
. . .
Special Treatment .,.
end
Who should check?
What the precondition means is that the
client must
guarantee
property
p;
this is
not the same as
testingfor
thiscondition
before each call. If the context of the
call implies
p,
then there is no need for
such a test. A typical scheme is
if new = Void then
The rejection of defensive program-
ming means that the client and supplier
are not both held responsible for a con-
sistency condition. Either the condition
is part of the precondition and must be
guaranteed by the client, or it is not
stated in the precondition and must be
handled by the supplier.
x.s; x.r
. . .
else
where the postcondition of s implies
p.
end
Using such a construction would de-
feat the purpose of having a precondi-
tion (Require clause). This is an abso-
lute rule: Either you have the condition
in the Require, or you have it in an If
instruction in the body of the routine,
but never in both.
This principle is the exact opposite of
the idea of defensive programming, since
it directs programmers to avoid redun-
dant tests. Such an approach is possible
and fruitful because the use of asser-
tions encourages writing software to spell
out theconsistencyconditions that could
go wrong at runtime. Then instead of
Which of these two solutions should
be chosen? There is no absolute rule;
several styles of writing routines are
possible, ranging from demanding
ones where the precondition is strong
(putting the responsibility on clients) to
tolerant ones where it is weak (in-
creasing the routines burden). Choos-
ing between them is to a certain extent
a matter of personal preference; again,
the key criterion is to maximize the
overall simplicity of the architecture.
*Assume that many clients will in-
deed need to check for the precondi-
tion. Then what matters is the Special
Treatment. It is either the same for all
calls or specific to each call. If it is the
same, causing undue repetition in vari-
ous clients, this is simply the sign of a
poor class interface design, using an
overly demanding contract for
r.
The
contract should be renegotiated and
made broader (more tolerant) to in-
clude the standard Special Treatment
as part of the routines specification.
The experience with Eiffel, in partic-
l
If, however, the Special Treatment
is different for various clients, then the
need for each client to perform its own
individual test for
p
is intrinsic and not
44
COMPUTER

Citations
More filters
Journal ArticleDOI

Review: A survey on security issues in service delivery models of cloud computing

TL;DR: A survey of the different security risks that pose a threat to the cloud is presented and a new model targeting at improving features of an existing model must not risk or threaten other important features of the current model.
Journal ArticleDOI

A survey and comparison of peer-to-peer overlay network schemes

TL;DR: A survey and comparison of various Structured and Unstructured P2P overlay networks is presented, categorize the various schemes into these two groups in the design spectrum, and discusses the application-level network performance of each group.
Proceedings ArticleDOI

Restful web services vs. "big"' web services: making the right architectural decision

TL;DR: This paper objectify the WS-* vs. REST debate by giving a quantitative technical comparison based on architectural principles and decisions and shows that the two approaches differ in the number of architectural decisions that must be made and in theNumber of available alternatives.
Journal ArticleDOI

Preliminary design of JML: a behavioral interface specification language for java

TL;DR: JML as mentioned in this paper is a behavioral interface specification language tailored to Java (TM) that allows assertions to be intermixed with Java code; these aid verification and debugging. JML is designed to be used by working software engineers; to do this it follows Eiffel in using Java expressions in assertions.

Preliminary Design of JML: A Behavioral Interface Specification

TL;DR: This paper discusses the goals of JML, the overall approach, and describes the basic features of the language through examples, intended for readers who have some familiarity with both Java and behavioral specification using pre- and postconditions.
References
More filters
Journal Article

An Axiomatic Basis for Computer Programming

Journal ArticleDOI

An axiomatic basis for computer programming

TL;DR: An attempt is made to explore the logical foundations of computer programming by use of techniques which were first applied in the study of geometry and have later been extended to other branches of mathematics.
Book

Systematic software development using VDM

TL;DR: Logic of propositions reasoning about predicates functions and operations set notation composite objects and invariants map notation sequence notation data rectification more on data types operation decomposition.
Journal ArticleDOI

System structure for software fault tolerance

TL;DR: In this article, the authors present a method for structuring complex computing systems by the use of what they term "recovery blocks", "conversations", and "fault-tolerant interfaces".
Frequently Asked Questions (1)
Q1. What are the contributions in this paper?

This article presents such guidelines, whose main goal is to help improve the reliability of software systems.