Design by Contract Contract Design
A Conversation with Bertrand Meyer, PART II BERTRAND MEYER Interview
Bi Bill Venners Interviewer: Bill Venners
December 8, 2003: 2003-12-8
Summary
Summary
.
BERTRAND MEYER and BILL VENERS discuss the limitations of contractual design and form languages in contractual representations.
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.
Bertrand Meyer is a software pioneer that is active in the second border of academic and business. He is currently chairman of the Software Engineering Association of the Swiss Institute of Technology. He has written a quantity of vocabulary papers and books, such as classic "object-oriented software constructs" (Prentice Press, 1994, 2000). In 1985, he founded an interactive software engineering company. The company has renamed Eiffel Software, providing software tools, training and consulting services based on Eiffel language.
On September 28, 2003, Bill Venners conducted a phone interview with Bertrand Meyer. In this interview, which will be 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.
September 28, 2003, Bill Venners did a telephone interview on Bertrand Meyer. In this interview (content will be announced in Artima.com, Meyer has made many relevant software issues, such as software quality, software complexity, contract design, and test drive development.
Designing Components That Fit Together
Assembly Bill Venners designed to work in synergy: In your book, Object-Oriented Software Construction, you write, "For a system of any significant size, the individual quality of the various elements involved is not enough What will count most is the guarantee. That for EVERY INTERE IS An Explicit Roster of Mutual obligation and benefits, the contract. "What is the contract? Why is it important?
Your "Object Software Construction" book: "For a large system, light ensures that the quality of its components is not enough. The most valuable is to ensure that the handover in any two components The design is clear and the right to obligations and rights norms, the so-called contract. "What is a contract? Where is its importance?
Bertrand Meyer: There are two quite separate points in that extract The first point is that when you're building a library, it's not enough to just accumulate good components Take a data structure library as an example You might have excellent classes for... lists, stacks, files, and btrees, but taken together they do not make an excellent library if they are inconsistent. If they use different conventions, they are not part of a single design. For example, when you're putting an element into an array, you might have an insert operation that takes x and i, where x is the element and i is the index. For the hash table class you might have an insert operation that takes key and x, where key is the key and x is the element. The order of arguments is reversed. The order of arguments might make perfect sense within each class, but when you start approaching the library as a whole, you're in new territory each time you look at a new class . You don't get a feputing of consistency. Instead you ge ta feeling of a mess-something that is a collection of pieces rather than a real engineering design. What we found many years ago when we started focusing seriously on libraries is that just as much attention has to be devoted to the construction of the library as A WHOLE AS to the Construction of the Individual Elements. That's One Point.
This issue is discussed from two independent aspects of each other. First, when you build a library, just designing each individual components or not enough. Take a data structure library. You have designed a good list, stack, files, and B tree, but if they are not coordinated, then when they put them together, you can't get a good library. You may be in a common place, let each class use different regulations. For example, when putting an element into an array, you need to have an insert operation with parameters X and i, where x is the element itself, i is inserted; for the hash table, one insertion operation requires parameters Key and X, Where Key is keyword, X is an element. Their parameter order is the opposite. Different parameter sequences are indeed very closely expressively expressing the meaning of the operation, but when you use this library as a whole, you are in a different class, you are like entering a strange field. Not only do you get a consistent, a coherent feeling, but feel confusing - that is a lot of fragments rather than engineering design. Many years ago, we found that more attention should be positioned on the entire library, rather than an integral part of the design. This is the first point I want to say. The second point pertains to how a library needs to be consistent, how its various elements can fit together like the pieces of a puzzle. It's not just a matter of defining consistent interfaces, order of arguments, things like that. It's also a matter of defining precisely how the various elements are going to communicate with each other and making sure that the conditions of this communication is very precisely defined. This is, of course, where the techniques of Design by Contract come in.
The second point is to say how to design a library to make it coordinated, and its many variable elements of all aspects of the factors contained in a problem can work together. This is not to define the compatible interface, parameter sequence, etc., and must also accurately define the mutual communication methods of each component, as well as the conditions required for communication. Of course, this is the content included in the contractual design technology.
Design by Contract
Contract design
Bill Venners: COULD you give an overview of design by contract?
Can you summarize the contract design?
Bertrand Meyer: People who have heard a little bit about contracts often think they are simply a way to put the equivalent of assertions in a program: that is to say, to put in a few checks here and there for conditions that are expected to hold at specific points of execution. Such assertions are basically debugging statements. The assertion code is executed during debugging, and if one of the conditions is found not to hold, execution usually stops with a message. That's one of the things you can do with contracts But it is only a small subset of the purpose of contracts. People who have earned earned people often think that the contract is just how to put things like an asserted thing in the program. That is to say, conditions are checked in some places to control the execution of the program. These asserters can basically see as debugging statements. The assertion code is executed during the debug phase, and if a condition is found, the corresponding information is usually given and the execution is stopped. This is indeed what you can do with the contract, but this is just a small subset in the contractual design purpose.
The main purpose of contracts is to help us build better software by organizing the communication between software elements through specifying, as precisely as possible, the mutual obligations and benefits that are involved in those communications. The specifications are called contracts. The underlying observation, which is not particularly deep, is that a software system is made of a number of elements that cooperate with each other. In an object-oriented architecture, these elements might be classes and methods, which I prefer to call routines. The elements might be something else in a different programming model, but let's just assume we are working in an object-oriented context. So we have a software system made of a number of classes, and these classes themselves contain among other things routines that are going to be executed and Call Each Other. so Both the architecture of the system and its Execution Rely ON A Large Set of Possible Communication Channels Between The Software . Elements The metaphor of contracts is used to guarantee that these communications occur not on the basis of vague expectations of services rendered, but on the basis of precise specifications of what these services are going to be the main purpose of the contract is: as accurate as possible It is equally obligated and right when software elements are communicating with each other, thereby effective organizing communications, helping us construct better software. The "provisions" are what we say "Contract". Through in-depth observation - not to refer to partial deepening - we believe that the software system is composed of a large number of collaborative elements with each other. In the object-oriented architecture, these elements can be class and methods (I prefer known as routines). In other programming modes, these elements can be other things, but here, we assume that it works in an object-oriented environment. In this way, our software system is composed of a large number of classes; these classes include many routines that will be modified independently. Therefore, both system architecture and system operations are attached to a large number of communication channels that exist between software elements. The meaning of the contract is to ensure that these communications are based on accurate rather than the service to provide services.
Typically in such a communication between program elements-for example, when one routine calls another routine-it's like a client / supplier relationship. The calling routine, which we will call the client, is performing some computation, probably for the need of its own client. In order to perform that computation, that is to say, to perform its own service, it needs services from some other software element, typically some other routine. So there is a client / supplier relationship, where the client needs a certain service And The support of the Basic Scheme Both The Client and The Supplier Are Routines. A typical example of communication between program elements. When a routine calls another routine, they constitute a client / service relationship. Call routines (we also call it client routine), which may be calculated in order to meet the needs of its own customers. In order to complete the calculation (or in order to complete the service you want to provide), it needs to obtain a service from another software element. Then there is a customer / service relationship - the client needs a service, and the server provides this service. In this very basic model, the client and the server are routines.
For the software and software designer to be able to guarantee any kind of correctness and robustness properties, they must know the precise constraints over such communications. This is where the contract metaphor from business applies to software. Say I'm contracting from you to have A Certain Business Operation Performed On My Behalf. for Example, Perhaps You Have a Part That I Can Use for a Product That I'm Manufacturing. So I'm Your Client, And You're My Supplier. in Business, We're going to organize our collaboration on the basis of a contract: a precise statement of the mutual obligations and benefits that we'll expect In software, we're going to do exactly the same thing when we write client and supplier routines..
For software and software designers, in order to ensure the correctness and robustness of all aspects, they must understand the accurate constraints of communications. In this place, we apply the contract concept in the business to the software. For my interest, I must make a constraint when you implement a certain business. For example, you may have some parts that can be used in the products I have developed. Then I am your customer, you are my service provider. In business, we will coordinate each other through the contract - the exact expressions of our expectations and rights. For software, we must strictly follow the same contractual representation when we write customers and service routines. So we're going, for example, to impose on the client certain obligations as to the kind of original program state that is permissible when the client calls the supplier or the kind of arguments that the client routine passes to the supplier. These are pre -conditions, and they're obligations for the client. In the other direction, we are going to express the conditions that the supplier routine must guarantee to the client, on completion of the supplier's task. that's the post-condition of the contract, Spectally, The Post-Condition of That Particular Routine. and of course
For example, what original program state is the necessary condition of the client call server, what type should be made to the client routine to the service routine, which is the constraint we want to make on the client. These are front conditions and is the client's obligation. On the other hand, in order to complete the service, we must also clarify the service that must be guaranteed to the client. This is the back conditions in the contract, in many cases, that is, the back conditions of a routine. Of course, the back condition is the obligation of the server.
Pre- and post-conditions are symmetric. The pre-condition of the routine is an obligation for the client, because the pre-condition says that before calling a particular routine, the client must satisfy a particular property. For the supplier, the pre -condition is a benefit, because it facilitates the supplier's job by restricting the set of cases that the supplier has to handle. The obligation of the client is a benefit for the supplier. The post-condition is of course an obligation for the supplier, because it describes the job that the supplier has to guarantee to perform. But the post-condition is clearly a benefit for the client, because it describes the result that the client is entitled to expect from the execution of the routine for the benefit of its OWN Problem Set. Pre-preamp and back conditions should be symmetrical. The front condition of the routine is the client's obligation, because the front condition specifies that the client must meet a specific requirement before calling a specific routine. For the server, the pre-conditioning is the right because it makes a constraint by a series of work that must be processed by the server, making the server's work more easily. The rear condition is of course the server's obligation because it describes the server to ensure processing. However, the back conditions are clearly the rights of the client because it describes the return result after the client is eligible for the execution of the routine execution, which is good for the client to solve its own problem set.
Before moving on I can describe a very simple example of pre- and post-conditions:. A routine that computes the square root of a real number The pre-condition would say that the real number has to be non-negative, because otherwise the Result 10 Be undefined. The post-condition may say That The result returned by the routine is the approximation, of the exact mathematical Square root of the routine.
Before ending this topic, I can give a simple example of the pre-and back conditions: one routine to calculate a solid square root. Then, the preamp requirement requires that the real number must be non-negative, because the square root of negative numbers are not defined. The rear condition can be expressed in this way: routine returns the closest square root in the previously specified precision.
So pre- and post conditions are two fundamental elements of contracts. The third fundamental element-which is really useful mostly in an object-oriented context, where we have not only routines but at the higher level, classes-is invariants. A class invariant is a condition that applies to an entire class. It describes a consistency property that every instance of the class must satisfy whenever it's observable from the outside. that means that this property, the class invariant, must be satisfied whenever an instance of the class is created. And every exported routine, routines that can be called from the outside of the class, must preserve it. that is to say, assuming the class invariant was satisfied before the routine was called, the routine must ensure that class invariant is again going To Be Satisfied on EXIT. IT'S AS INVARIANT IS Added to the Pre- and Post-Condition of Every Single Exported Routine of The Class. But More Fundamentally, a class invariant is a way to to Characterize The Fundamental Consistency and Integrity Properties of The Class and ITS Instances. Therefore, the preamp and back conditions are two basic elements of the contract theory. The third element (it is actually very useful in the object-oriented field, so we are not only in routines, but often used in higher levels - class) is an invariant. Class invariance is applied to the entire class. Class invariance describes an attribute that each instance of the class must ensure that it is consistent at any time that is visible to the outside. This means that no matter when creating a class instance, the consistency of this attribute (or unchanged) must be ensured. Any exposed routine (the routine that can be called from the class) must protect it; Variation is met. In this regard, the class invariance seems to be attached to the preamp and back conditions of the class exposure routine. However, fundamentally, class invariance is a method of portraying basic consistency and integrity of classes and class instances.
For example, if you have a bank account class with a field that represents the current balance and a field that contains a list of all deposits and withdrawals since the opening of the account, then you would have a class invariant that states that the value of the balance field is equal to the total of all the deposit values so far minus the total of all the withdrawal values so far. It's typical that class invariants define properties that indicate how the various constituents of the class, such as balance and deposit / withdrawal For example, you have a bank account class that contains a field that represents the current balance and a field containing all savings and support in the account since the opening, then you should have a class invariant. It indicates that the value of the balance field is consistent with the accumulated savings and accumulated materials. This typical example shows that the class invariant definition property indicates how variable elements (such as balances and storage / menuments) maintain each other.
Pre- and post-conditions and class invariants are not the only elements of contracts. There are also loop invariants and a few others, but pre- and post-conditions and class invariants are really the basic fabric of contracts. In my experience, relying on these notions-that is to say, making sure when you write software that do not just write the implementation, but also write the more abstract properties underlying the implementation in the form of contracts-provides a greatly added software development experience in several respects . It helps ensure correctness in the first place, helps debugging, helps testing, helps ensure inheritance is properly handled, helps managers, provides a quite effective form of documentation, and a few others.
The elements of the contract are not light, post-conditionation, and clasped. There are also cyclic invariance, etc., but the preamp, post-conditionation and class invariance are basic elements. According to my experience, relying on these concepts - means that when you develop software, don't pay attention to the implementation of the implementation, you should also provide some more abstract performance in accordance with the contract of the contract - you can greatly increase from several aspects. Your software development experience. It helps you ensure that the software is correct, allowing the software to facilitate debugging, testing, facilitating the correct processing of inheritance, helping managers, and providing a very effective document establishment, and so on. THE LIMITS OF FORMAL LANGUAGES
Limitations of form language
Bill Venners: Are The The a in et ompsible to express in a formal language, That you can online?
In form language, whether certain parts of the contract are difficult or unable to express, but can only be expressed by human language?
Bertrand Meyer:. The simple answer is yes There are really three reasons why it sometimes feels hard to express a contract in terms of a programming language As a background, the way contracts are expressed in Eiffel is very simple:. They are just Boolean expressions . Boolean expressions are intended precisely to express runtime true or false properties-properties that at any point in the execution may hold or not hold. that's exactly how Boolean expressions are used, for example, in an if-then-else construction. that's also how they are used to express contracts in Eiffel, with one major extension:. the old keyword The old keyword makes it possible to express in a post-condition that a certain property at the completion of a routine is relative to a certain property on entry To the routine. if you have, for example, a routine That Adds a Certain Amount of Money To A Bank Account, Obviously The Post-Condition of this Routine Is Going to Have to Express That The New Balance Is Related T o the old balance. The new balance must be the balance before the execution of the routine plus some amount. The only way to express this properly is to have some notation to refer to the original value of the balance. So with this major, but SINGLE, EXTENSION, The Language of Contracts in Eiffel Is Just The Language of Boolean Expressions.
It is like this. There are three reasons in the actual fact that people sometimes feel difficult to express contracts in the programming language. First, a background, in the Eiffel language, the method of the expression contract is very simple - just use Boolean expressions. The design intent of the Boolean expression is to express the current value of true or false properties. At a moment, it is possible to determine whether the execution will continue at a time. This is the use of Boolean expressions, such as in an IF-THEN-ELSE block. In Eiffel, plus a primary extension - introduced "OLD" keyword - can express the contract by this method. The OLD keyword makes the two relationships of the attributes and the attribute before the beginning of the presentation routine before the retrofit. For example, you use a routine to accumulate a certain amount of deposits to a bank account, so obvious, the back condition of this routine must express the relationship between the current balance and the past balance. The current balance must be the sum of the balances before the execution of the routine. The only way to correctly express this relationship is to use a symbol reference balance. Therefore, after this major but simple extension, the Eiffel's contract design language can actually see the Boolean expression language. There are three occasions in which this approach of using Boolean expressions may appear restrictive. One occasion that is justified-where you will have to resort to human language descriptions instead of formal ones-is when you have externally visible properties. For example, if you have in a graphical library an operation that changes the color of a certain pixel on the screen to red, you'd like to describe a post-condition that says the resulting color is red. Maybe to some extent you can do that, but what you really want to express is that if a person is sitting at a terminal, and the person is not color blind, he or she will accept that the new color is red. Clearly this kind of assertion can not be expressed in a formal language, because it refers to properties outside of the realm of the software program. in practice it may not be such a big deal, because what you usually want in practice is not necessarily the guarantee that someone accepts the color as red, but the guarantee th At The RGB Value of The Pixel Being Displayed Is Within a Certain Range. And Of Course That Can Be Expressed As a Purely Boolean Property.
In three cases, the use of Boolean expressions can be used to express the contract may appear to be from the heart. The first case is that when you use the attribute to express physical visibility, you have to use the human language to judge, and the form language is unobstructed. For example, one of your graphics library is to set the color of some point on the screen to red, then you generally use a back condition to express the final color of this point is red. To a certain extent, you will do this, but in fact you really want to express: There is a person sitting in front of the computer, this person is not a color blind, he / she recognizes that this is red. Obviously, such an assertion cannot be expressed in a form language because it describes the properties of the software language range. Of course, in practice, this has not been made to do, because usually, we don't guarantee that someone recognizes that the color is red, but to ensure that the RGB value of the pixel display color falls in the specified range. Of course, this can be expressed in a pure Boolean property. The second occasion where Boolean expressions may seem restrictive is one that scares most people who have looked at the issue from a theoretical perspective: the language of Boolean expressions is relatively limited and does not have first-order predicate calculus This has led some people. who design the specification mechanisms for programming languages, or in the case of UML, for modeling languages, to include facilities from first-order predicate calculus as a language extension. I think that is largely a mistake. At least we do not need to do this in Eiffel, because we have a high-level mechanism known as agents to describe essentially high-level functional operations on objects. So anything that you may want to express on a complex object that would seem to require first-order predicate calculus can BE Expressed Actually Quite Nicely With In Confines of The Programming Language.
Many people have been in theory from the theoretical perspective, and the second case of Boolean expression is found to be smashed by the language of the Boolean expression, because there is no first order predicate calculation characteristics. This has promoted some of the first-order predicate calculations in the programming mechanism and modeling language of the programming language (such as unified modeling language, UML), as a function extension. I think this is a big misunderstanding. At least in Eiffel, we don't need this because we have a high level of mechanism called agent to describe a high level of functional operation on the object. So for a complex object, anything that looks like a first order word calculation can actually perform very finely expressed in the programming language.
What is quite easy to express with Boolean expressions, for example, is a property that if you're adding an element at the end of a list, the last element of the list is now the one that you just added. That's quite easy to express, and it's definitely expressed in the corresponding Eiffel concept. What is less easy to express is the property that all the other elements of the list, the ones that you have not touched, are still there, in the same order, and are equal to their previous values. This kind of assertion seems to require special language extensions and has led people to suggest introducing first-order predicate calculus. But what we've found is that apart from the agents mechanisms, which has been in Eiffel now for a number of years, there's really no need for introducing first-order predicate calculus, or there exists operators. We can basically express those assertions in the realm of the programming language. for example, if you are adding an element to the end of the list, The last element of this list is the element you just increase. This attribute is very easy to describe, and the corresponding theory in Eiffel is clearly explicitly expressed. It is not easy to describe that all other elements you have never been moved in the list, they are still in place, sequential and values remain unchanged. In this case, the assertion seems to realize a specific language extension, so some people recommend the first order predicate calculation. However, we have found that there is already a proxy mechanism that has existed in Eiffel, it can be solved, and it is not necessary to introduce first-order predicate calculations and the the exists operator. In the programming language, we can basically express these assertions.
Also, first-order predicate calculus is not good enough anyway. A typical kind of property that you might want to express, say, in a class invariant for a graph class, is that the graph has no cycles. This is not expressible as a first-order predicate calculus property. On the other hand, it is expressible as a Boolean expression if you accept including function calls in the Boolean expression. So that particular argument for extending the assertion language or for expressing contracts in English goes away at least in the long term. in the short term, these techniques of expressing high-level ambitious properties are still under development, and you will still find for that kind of property assertions expressed informally as comments. Meanwhile, in every way, first order The predicate calculus is not good enough. For example, in a map class, the typical attribute you may want to represent is that there is no loop. This is the attribute of a first-order predicate calculation. But change the angle, if you allow implantation of the function call in the Boolean expression, it is a Boolean expression that can be expressed attributes. Therefore, there will be a debate on the expansion of the contract language and the appointment in English, will be silent after a longer period of time. During the short period, the technique of expressing high complex properties will still be in the development stage, but you can find informal, annotative assertion representations for such attributes.
The third occasion where defining contracts using Boolean expressions raises issues is non-functional contracts. Maybe I should not go into this too much, because this is more of a research issue. Nevertheless, once you have completely expressed all the functional contracts-the contracts that specify what the input may be to operations, what outputs are legitimate, and what globally consistency constraints must be maintained-you might still want to express as part of the specification things like: this operation will always execute in less than half a millisecond , or this particular component will never use more than 300 kilobytes. These are performance contracts, and it's a quite interesting research area. I think there will be usable results in this area in the next few years, but it falls beyond the realm of Design By Contract As It Is Generally Understood In Practice Today. The third condition for the use of Boolean expression definition contract is in a non-functional contract. Maybe I can't say too much, because this is still a research topic. However, in all the functional contracts, these contracts specify the legal input, output, and global consistency constraints that must be maintained - after the expression, you may also want to express the following content: This operation should be half Completed in milliseconds, this component consumes no more than 300KB. These are a performance contract, and it is also a research area that is interested in. I think, after some years, this area will have practical results, but it has exceeded the category of contractual design. In practice, we can generally understand this.
Bill Venners: That Was Actually My Next Question: Is Performance Part of The Contract? It does See Performance is Important in The Contract Sense. People Want Quality of Service Guarantees.
This is precisely the next question I prepared: How does the contract express in operation performance? It seems that performance is also very important from the perspective of contract. People need high quality service guarantee.
Bertrand Meyer:... Right Absolutely It's very important I think everyone realizes this The problem is that it is pretty difficult to ensure and test And it also has to be defined properly When you define, for example, a response time,... is it a minimum response time? Is it a maximum response time? Is it an average response time? If so, what is the statistical distribution? I do not think these questions have no possible answers, but they make the issue quite delicate. And They Have No Direct Counterpart with Functional Contracts. So Performance Contracts Are Definitely An Area in Which More Work Is Needed and actually is being performed. It is absolutely correct. It is very important. I think everyone recognizes this. The problem is that the guarantee and testing of this is very difficult. It also needs to be accurately defined. For example, you define a response time, then it is the minimum response time, or the maximum response time, or the average response time? Then, what is the statistical distribution look like? I don't think there is no possible answer to this, but these questions make problems very difficult. Therefore, the performance contract has been classified into a special field that needs more efforts. In fact, this area has been in progress.