dits:
CP added new roger lede; I fixed all the hyphens and dashes and gave it a
once-through read, tc
[Appeared
in Software Development, July 2000 or thereabout. Copyright Software
Development magazine.].
[Pullout quote:
Interface Definition Languages as we know them today are doomed.]
It’s
sometimes only after a technology has established itself that one can start to
understand what it really is about. In the case of component-based development,
I hope that we can do better. The three co-columnists (Bruce Powell Douglas,
Clemens Szyperski and I) are trying, each with our own separate voice,
background and interests, to analyze the technology as it happens. Not just
analyze but influence too: since we are all active participants in the field,
rather than dispassionate observers, we all have a vested interest to make sure
that it happens right and fulfills its promises. As I have hinted in earlier columns, one of
the incontrovertible conditions is that we properly tackle the issue of
specifying components. The word “contract” has already been tossed out a few
times in this respect (by myself as well as Clemens and Bruce), and it’s time
to see more closely what it means for components.
Component-based
development is still very new, but we are starting to have enough perspective
to see what it’s about. Components as we have them today result, I think, from
the confluence of two major developments of the nineties:
(I must
also mention a third phenomenon, without which none of this would have
happened: the general
trend towards standardization of interfaces, most visibly through the universal
deployment of the Windows API, Linux’s potential notwithstanding. As this is
the background for much of the extraordinary recent development of the computer
industry, we don’t need to delve on it further.)
The major
component standards — COM, CORBA, EJB — attempt to capitalize on the power of
object-oriented principles to generalize “controls” to full-fledged software
components, similar in spirit to the tangible components of other engineering
disciplines (electronics, machinery…), and applicable to any software need, not
just user interfaces. What is still missing in this effort, however, is a
standard way to specify the components.
In his
book on Component Software, Clemens Szyperski rightly points out that
software components differ in some intrinsic ways from engineering components
in (for example) electronics. These differences are natural since the analogy
with electronics is only a metaphor, and not all properties from one field
apply to the other. A metaphor is not an identity. But one property of
components applies to any field of engineering: we cannot seriously have
component-based development without developing, for every component, a
specification of the component, distinct from the component itself, and serving
as the sole basis for users (“clients”) of the component.
Why is
this rule, so obvious in all other fields, not universally applied in software?
The answer, I think, lies in the specific nature of software and the fuzziness
that it creates between description and described. The just stated requirement
that the specification should be “distinct from the component itself” is a
platitude in electronics or construction engineering: no one would confuse a
circuit with a circuit diagram, or a bridge with a map of the bridge. You can
fall from the bridge, but not from the map. You won’t usually get an electric
shock from the circuit diagram. Remember the famous Magritte painting of a pipe, entitled “Ceci n’est pas une pipe” (this is not a pipe.) But with
software the platitude turns into a tricky question, because separating
specification from implementation is not that straightforward any more. Otherwise
we wouldn’t be screaming at each other, during design discussions, things like
“But this is only an implementation matter!”. And information hiding wouldn’t
be such a key issue.

I cited
information hiding, in my first column, as the key determinant of the appeal of
binary component standards, noting that binary components make information
hiding inevitable. But information hiding, and components in any decent form,
can only work with a specification. You can only trust components to the extent
that you know what they do. This is where current approaches don’t quite
deliver yet.
Both the
CORBA and COM standards use, as one of their central concepts, an Interface
Definition Language. It’s a little confusing because they use the same name and
acronym, IDL, for two distinct languages. But this shouldn’t bother us here
because the two IDLs are in fact quite close in their concepts. If you don’t
know IDL (in either variant), you in fact almost know it anyway if you have
done any C++, since an IDL class specification is very similar to a C++ header
file — the part that gives the signature of the operations, without their
implementations. Here for example is a CORBA IDL specification of a function
from a component in charge of making airplane reservations:
boolean ReserveFlight (in Seats
places) raises (InvalidSeat, SeatAlreadyBooked);
This says that the component offers an operation ReserveFlight that expects as argument a list of seats to be reserved, returns a boolean value (presumably an indication of success — personally I would never use such side-effect-producing functions, but this example illustrates the prevalent programming style), and may raise certain exceptions in case things don’t go as smoothly as we would like.
Studying current IDLs leads to two immediate remarks. The first is that IDLs as we know them today are doomed. Not the notion of interface, but the idea that you should write an interface as a separate effort. For a few stable components it may work; but in the long term this is a broken approach for at least two reasons:
This is why the standard CORBA approach of writing an IDL spec and using an IDL compiler to generate a module template in a programming language seems to go the wrong way around. You should concentrate on writing the software, and let tools produce its interfaces. This rule is not affected by the observation that, in most cases, you can’t extract a class from a normal O-O system and make it into a component, but need instead to write a few interface classes to serve as your application’s component façade to the rest of the world: even so, you will want to write your façade classes in your programming language of choice, not yet another formalism.
A number of CORBA tools are now available to do just that — decompilation into IDL. In the COM world, ISE’s EiffelCOM wizard (http://eiffel.com/products/com) enables you interactively to wrap Eiffel applications into COM components, and other languages’ COM components into Eiffel façades for use from Eiffel. It seems clear anyway that the evolution of COM technologies, as will be described in my next column, will move away from IDL as something that must be coded separately.
Separateness is not the only problem of the current IDLs. Their most striking limitation has been mentioned in earlier columns: they stay within the limits of purely structural specifications. The above specification of ReserveFlight says very little in terms of actual semantic specifications. It gives the name of the operation all rights, the number and types of its arguments, and the list of abnormal cases it is prepared to encounter and signal, but nothing about what it actually does.
Yet this is the kind of thing that we would expect from a specification in the full sense of the term. An electrical component’s spec will tell us about global operating conditions (temperature and so on), acceptable input signals (voltage and amperage limits), output signals as a function of the input, all this independently of the specific implementation technology. We need the same three kinds of specification elements for a software component:
These concepts of Design by Contract have been extensively applied to the development of object-oriented software in Eiffel, where they are part of the basic fabric of the language, and are increasingly being applied to other approaches such as Java (through tools like iContract), C++ (through macro packages like Nana), UML (through the Object Constraint Language). For links to references on these tools and many others, see the designbycontract.com portal described in the sidebar.
The
concepts are even more necessary in connection with component standards such as
CORBA, COM and EJB since, as I pointed out in an earlier column, “it’s
information hiding, stupid”: with binary components we don’t have the last
resort of going to the source code. Yet a specification such as the above is
badly lacking in this respect. The closest it comes to specifying the semantics
is by listing the exceptions. But this leads to a programming style heavily
based on exception handling, which is not healthy; and of course it is rather
paradoxical that we should specify to our clients what abnormal
conditions can arise, but not take the trouble to tell them what the normal
expected behavior is!
A number of proposals have been made to add contracts to CORBA and COM; again, look at designbycontract.com for pointers. We are currently building a language-independent contract framework for COM, which I will describe in a later column.
As Clemens Szyperski hinted in one of his last columns, transposing the notion of contract from the world of classical programming to the world of component-based development raises a few challenges. We can point out the following problems:
·
In a
development environment such as Eiffel, iContract or Nana, we may expect to use
contract monitoring for development, then turn it off for execution. With
components, we may have to keep contract verification on all the time.
·
The
very semantics of contracts changes in a concurrent, development environment.
In the OOSC book I discuss at length the SCOOP model (Simple Concurrent
Object-Oriented Programming) which fundamentally relies on contracts, but with
preconditions reinterpreted as wait conditions (in fact, the basic
synchronization mechanism) rather than correctness conditions.
·
The
expressiveness of the contract language is important. There has been much
progress recently in this area, with such developments as OCL (the Object
Constraint Language for UML) and new high-level contract-oriented mechanisms
for Eiffel, described in my June column in JOOP (“Towards more expressive
contracts”).
·
There
may be more than only level of contractual properties.
On the last point, my colleagues Christine Mingins and Jean-Marc Jézéquel (whom I plan to invite to contribute a guest column later in this series) distinguish four levels of contracting: basic type contracts, such as exist in typed programming languages as well as the current IDLs; semantic contracts, such as the ones cited above, expressing invariants, preconditions and postconditions; performance contracts, so critical for example in real-time applications; and quality of service contracts, harder to quantify but just as important in practice, as anyone who has tried to access his E*Trade account at the time of highest market volatility (such as the time of writing this column) will have noted.
The general idea of the Trusted Components effort (http://www.trusted-components.org) is to explore these issues to find out if we can build a repertoire of high-quality components — components to which we can really entrust the reliability of our applications.
The difficulty of these issues explains why I haven’t yet included
in the present column a description of my proposed CDL (Contract Definition
Language) as announced in the previous installment. I realized that this was
still premature; we need first to explore the background in some depth. Later
columns will continue in this direction, and will at due point include the CDL
proposal.
In the meantime, it is essential to note that no good component
can exist without a good specification. Even if you do not have access to
languages and tools officially supporting the Design by Contract methodology,
the time to start using the principles is now. The good news is that it’s not
difficult. We are not talking about fully formal approaches, such as
Jean-Raymond Abrial’s B method and tools, described in his B Book (Cambridge
University Press, 1996 — surgeon general’s warning: not your typical Stephen
King, and not for the mathematically faint of heart), and used recently to prove,
mathematically, the correctness of the security aspects of the latest,
driver-less, line of the Paris metro, a 100,000-line program. For most of us,
this is still beyond our reach. We are talking about something much simpler —
the three questions. In Design by Contract we keep asking three questions: What
does it maintain? What does it expect? What does it guarantee? You will of
course have recognized in these questions the notions of class invariant,
operation precondition, and operation postcondition. Don’t ever write any
component, in any sense of the term (my and Bruce’s broader sense, or Clemens’s
narrower one), without asking the Three Questions of Software Contracting.
Component-based development, and just good software development, comes at that
small price.