Presentation on theme: "Design by Contract. Design by contract is the process of developing software based on the notion of contracts between objects, which are expressed as."— Presentation transcript:
Design by Contract
Design by contract is the process of developing software based on the notion of contracts between objects, which are expressed as assertions.
Design by Contract Object oriented software development builds on this familiarity by providing a traceable path from real-world objects through their conceptualisation during analysis and their construction during design, to their use during implementation. In the end, the objects that you implement become the software system.
Design by Contract One way to ensure that a software system performs its intended functions is based on the concept of a contract. When an object sends a message to another object, a form of contract exists. The receiver is being asked to perform a service for the sender. The sender is viewed as a client that requests a service from a supplier (the receiver or server). Whenever a service is provided, a contract comes into play: the client expects the supplier to perform the service correctly and the supplier expects to be asked to perform only those services it knows how to supply.
Design by Contract If either of these expectations is not met, the contract has been broken. Identifying roles in terms of clients and suppliers (servers) enables designers to specify the responsibilities of objects more precisely; this allows clearer software to be built which, in turn, leads to greater confidence in the correctness of the software i.e. the users requirements are being met. The process of developing software based on contract between objects has come to be known as Design by Contract.
The contract to produce quality software Use cases provide a language for describing requirements that aim to be understandable to both technical (developers) and non-technical (customers and users) people. A significant part of a use case consists of the pre-condition and post-condition that constrain it. Pre-conditions, post-conditions and invariants are collectively known as assertions. These can be used to build contracts. To the customer (or software purchaser) many assertions will appear as business rules.
The contract to produce quality software A scenario is a description of a sequence of actions that illustrate a piece of interesting behaviour. Just as an object is an instance of a class, a scenario is said to an instance of a use case. In the UML, a scenario describes the interaction and dialogue between the users of a software system (its actors) and the software system itself. For a given use case, we expect to see one main scenario that describes the flow of events leading to a successful conclusion. There may be other scenarios that describe alternative or additions to the main scenario.
The contract to produce quality software Assertions can be introduced early in the development process, during analysis as contract on use cases. As development progresses so the assertions will be refined with more detail being added and carried through into design and then into implementation.
The contract to produce quality software Assertions can be included in the final code to be checked both by the compiler and by the run-time system. Ultimately, the contract is embodied in the code and we have a traceable pathway from analysis to implementation that shows how the assertions were developed and relates the code directly to the requirements. This process is known as Design by Contract or DbC for short.
Contracts in the real world –In the general case: a suppliers services will still satisfy a request if their constraints on inputs (pre-conditions) are a slackening (DbC calls it weakening) of the requirements on inputs, and/or their constraints on outputs (post-conditions) are a tightening (DbC calls it strengthening) of the requirements on outputs.
Advantages of DbC –There are four main advantages to this approach: –1 assertions provide accurate documentation for the implemented classes so that a programmer knows how to use the classes and what to expect from them; –2 provided they are executable, assertions are an important aid to testing, but without being an obstacle to efficiency;
Advantages of DbC –There are four main advantages to this approach: –3 assertions provide a way of controlling inheritance in which substitutability and redefinition of methods are allowed; –4 provided the programming language has an exception mechanism that accords with the principles of DbC, assertions together with the exception mechanism can be an important aid to developing mission critical systems.
Contracting, subcontracting and inheritance –One way of describing what each task, activity or operation should achieve is to write a form of contract as follows: 1 a description of the task, activity or operation in question; 2 a set of constraints that are assumed to be true before you can start, which is known as a pre-condition; 3 a set of constraints that must be true afterwards, which is known as a postcondition.
Contracting, subcontracting and inheritance –The aim is to describe the state changes required of an operation, activity or task without having to say how they might be achieved. Each contract tells you about the constraints on the expected behaviour of an operation. In effect, the design can be deferred while you focus on what must happen.
Contracting, subcontracting and inheritance –In the context of software development, a contract is between two objects: the client object and the supplier object. The contract comes into effect when the client uses one of the services that the supplier object provides. Since the client object wants the server object to do something for it, you can view this relationship as a contract, similar to the one we looked at above, with conditions on inputs (pre-conditions) and outputs (post- conditions).
Contracting, subcontracting and inheritance –As an example of how a contract works, consider a bank account system in which there is a method for withdrawing an amount of cash from an account. If there is a limit on the amount by which the account can be overdrawn, we can specify what the method should achieve and what should be true before the method should be invoked, as a contract with the following pre- and post-conditions: –pre-condition: there must be sufficient funds in the account; –post-condition: the account will have been debited by the requested amount.
Obligations and benefits on both client and supplier –that the pre-condition must be satisfied means the client must ensure that there are sufficient funds in the account for the amount to be debited, but the supplier does not need to check that there are sufficient funds (if the pre-condition is not satisfied, the client cannot expect to get the service it would like); –that the post-condition must be satisfied means the supplier must debit the amount from the account, and the client receives the service that it requires. (supplier incorrect.)
Discovering Contracts –When defining contracts, new classes, attributes or associations will be discovered, so existing classes may have to amended Ask two questions: –pre-condition: What is needed for this operation to be allowed to start? –post-condition: What will have happened as a result of this operation?
Subcontracting and inheritance The generalization relationship requires the use of the substitutability test to determine whether one object was a generalization of another: if an object of one type can be substituted for an object of another type in all circumstances, the type of the first object is a subtype of the second; that is, the second object is a generalization of the first.
Subcontracting and inheritance When we come to examine the idea of subcontracts in software we must bear in mind that objects relate to one another in two basic ways: 1 through associations (e.g. has-a); 2 through generalizations (the is-a relationship). Also, instances are related to classes.
Subcontracting and inheritance If the objects of the subclasses are to be substitutable for those of the parent class, a certain relationship must hold. This relationship can be expressed in terms of the pre- and post-conditions associated with the overridden methods in the two classes.
Constraints on behaviour –We can constrain the behaviour of the system in terms of: objects that are created and/or destroyed; links between objects that are created and/or destroyed; attributes whose values are changed.
Constraints in general Pre-condition: Describes something that must be true when client sends message. Post-condition: Describes something that must be true when the server completes operation. Class invariants: must always be true e.g.#onPlane<=MaxAllowed must be true. Type constraints: limiting operations Multiplicity constraints e.g. 1:M. Object Constraint Language OCL handles constraints in general.
Design by contract What does inheritance mean in relation to DbC? Overridden methods must conceptually do the same job. Demand no more: promise no less. Demand no more: a subclass must accept any message and arguments that the superclass accepts. Therefore a subclass preconditions must be no stronger than that of the superclass.
Design by contract Demand no more: Promise no less. Promise no less: any assumptions which were valid when the superclasss implementation was used should still be valid for the subclass implementation. Therefore the subclasss post- conditions must be at least as strong as the superclasses post-conditions.
FROM REQUIREMENTS TO CODE In an OO system, pre- and post-conditions can be related to a client–supplier contract between objects and how they can be usefully employed in the process known as DbC. Part of the value of DbC was that it allowed traceability from requirements through to code. We need an initial encoding of requirements as assertions. These must be transformed into assertions about code. DbC can improve the documentation of classes, but linking these requirement and code assertions.
DbC helps to move from requirements to code To move to code we need to: describe the relationship between invariants, and pre- and post-conditions, in English; use assertions to express contracts between the components of a simple system; write assertions in the OCL language; incorporate these assertions into a Java interface in a way that captures the specification of its behaviour and supports the notion of DbC; implement both the supplier and client code in accordance with a simple contract; Note the difference between a conditional statement and an assertion.
Monitoring assertions At high level errors and defects can be defined as: –errors = problems found before release –defects = problems found after release However in programming terms the term defect can be defined as an implementation that does not comply with a specification.
The role of assertions Assertions are used for a different purpose: they are ways of describing the conditions under which software elements will and will not work (pre-conditions) and the conditions that they will achieve (post-conditions). If the supplier and its clients are correct, that is, keep to their contract, assertions should always evaluate to true. In other words, an assertion violation, which would be detected at run-time, is an indication of a defect in the software.
The role of assertions To Repeat: An assertion violation, which would be detected at run-time, is an indication of a defect in the software with respect to its specification. A pre-condition violation indicates a defect in the client. A post-condition violation is a defect in the supplier.
The role of assertions The use of precisely defined contracts clearly assigns all responsibilities to either the client or the supplier. The stronger the pre-condition, that is, the more restrictive it is, the higher the burden on the client (there are more conditions to be satisfied before the client is allowed to invoke the supplier) but the easier it makes the task of the supplier. In practice, it has been found that designs that concentrate on doing a well-defined job are more successful than those that try to handle too many cases. In terms of pre-conditions, this implies that stronger pre- conditions are better than weak ones. Note that this strengthening needs to be balanced with the benefits that accrue from the weakening of pre-conditions e.g. easier to use?
FROM REQUIREMENTS TO CODE: The subtyping contract Demand no more: promise no less. What does this mean for behaviour of a subclass? Overridden methods must conceptually do the same job as the method in the superclass. Demand no more: a subclass must accept any message and arguments that the superclass accepts. Therefore a subclass preconditions must be no stronger than that of the superclass. (Roughly: should not turn off inheritance)
FROM REQUIREMENTS TO CODE: The subtyping contract Demand no more: Promise no less. Promise no less: any assumptions which were valid when the superclasss implementation was used should still be valid for the subclass implementation. Therefore the subclasss post- conditions must be at least as strong as the superclasses post-conditions. (Roughly: inheritance is strict extension not a reduction)
DbC can be used to ensure that the behaviour of inherited operations make sense. The is-a relationship is a way of determining when the concepts behind the classes are related through inheritance. For a subclass to be a subtype, each instance of it must respond to the same operations as instantiations of the superclass.
What is the important feature of DbC, which shows that it can be used to improve quality? Solution DbC allows the development of a software system to be traced from requirements through to code.
Client/Server In a system using Design By Contract what is the relevance of invariant, pre-conditions and post-conditions to: The client object which uses an operation? The server object which provides an operation?
Clients/suppliers Clients are responsible for ensuring preconditions are met, they can assume the post-conditions hold after the operation has been performed providing the preconditions are met. Supplier can assume that the pre-condition hold if they trust the client. It is also responsible for ensuring post-condition hold if the pre-condition are met. It must ensure that the invariant holds when an object is created and after every method call on that object.
Main advantages of using design by contract 1) traceability of assertions from analysis to implementation allows the developer to associate runtime activities or errors with design artefacts, hence a runtime error may be traceable to a design decision or design refinement. (a use case). 2) a (semi) formal way of stating correctness, the implementation respects the invariants, pre/post conditions in the specification. This can be agreed upon by both developer and client to be correct with respect to the specification.
Additional advantages of using design by contract Using design by contract means that assertions can be introduced early in the development process, during analysis. As development progresses so the assertions will be refined with more detail being added. Assertions can be carried through into design and then into implementation. Importantly, assertions can be included in the final code to be checked both by the compiler and by the run-time system. Ultimately, the contract is embodied in the code and we have a traceable pathway from analysis to implementation that shows how the assertions were developed and relates the code directly to the requirements. At the implementation level, if the software representing the client and supplier meets its contract we can say that the software is correct with respect to its specification.
DbC and class hierarchies A subclass is supposed to be able to fulfil the contract entered into by the superclass. An object of a class subclass should be substitutable for an object of the superclass. An object of a subclass is supposed to be usable everywhere that the superclass is. If the subclass is supposed to be able to fulfil the contract entered into by the superclassthen the overridden methods must conceptually do the same job. Assertions implemented in hierarchies should obey the following rule: Demand no more: promise no less. Demand no more: a subclass must accept any message and arguments that the superclass accepts. Therefore a subclass preconditions must be no stronger than that of the superclass. Promise no less any assumptions which were valid when the superclasss implementation was used should still be valid for the subclass implementation. Therefore the subclasss post-conditions must be at least as strong as the superclasses post-conditions.
DbC and class hierarchies Contracts are inherited, just like methods. When a method is overridden in a subclass, that class may specify its own contracts that modify those of the superclass method. A subclass method must: Accept all input valid to the superclass method. Meet all guarantees of the superclass method.
DbC and class hierarchies The overridden method may "weaken the precondition and strengthen the postcondition". The preconditions for the subclass method are logical or-ed with the super class preconditions. The postconditions are logical and-ed. This requires that the subclass accept all input valid to the super class method, and may accept more that is invalid to the super class. However, it must abide by the guarantees made by its parent, though it is given the option of strengthening those guarantees
Contracts and inheritance (Eiffel) An important consequence of the Design by Contract theory is to yield a better understanding of the central object-oriented notions of inheritance, polymorphism, redefinition and dynamic binding. A class B which inherits from a class A may provide a new declaration for a certain inherited feature r of A. For example a specialized implementation of DICTIONARY might redefine the algorithm for put. Such redefinitions are potentially dangerous, however, as the redefined version could in principle have a completely different semantics. This is particularly worrisome in the presence of polymorphism, which means that in the call a.r
Contracts and inheritance (Eiffel) the target a of the call, although declared statically of type A, could in fact be attached at run time to an object of type B. Then dynamic binding implies that the B version of r will be called in such a case. This is a form of subcontracting: A subcontracts r to B for targets of the corresponding type. But a subcontractor must be bound by the original contract. A client which executes a call under the form if a.pre then a.r end must be guaranteed the contractually promised result: the call will be correctly executed since the precondition is satisfied (assuming that pre implies the precondition of r ); and on exit a.post will be true, where post is the postcondition of r.
Contracts and inheritance (Eiffel) These observations shed light on the true significance of inheritance: not just a reuse, subtyping and classification mechanism, but a way to ensure compatible semantics by other means. They also provide useful guidance as to how to use inheritance properly.