Unformatted text preview:

Procedure Specifications 6.170 Lecture 4 Fall 2005 5.1 Introduction In this lecture, we’ll look at the role played by specifications of methods. Specifications are the linchpin of team work. It’s impossible to delegate responsibility for implementing a method without a specification. The specification acts as a contract: the implementor is responsible for meeting the contract, and a client that uses the method can rely on the contract. In fact, we’ll see that like real legal contracts, specifications place demands on both parties: when the specification has a precondition, the client has responsibilities too. Many of the nastiest bugs in programs arise because of misunderstandings about behavior at interfaces. Although every programmer has specifications in mind, not all programmers write them down. As a result, different programmers on a team have different specifications in mind. When the program fails, it’s hard to determine where the error is. Precise specifications in the code let you apportion blame (to code fragments, not people!), and can spare you the agony of puzzling over where a fix should go. Specifications are good for the client of a method because they spare her the task of reading code. If you’re not convinced that reading a spec is easier than reading code, take a look at some of the standard Java specs and compare them to the source code that implements them. Vector, for example, in the package java.util, has a very simple spec but its code is not at all simple. Specifications are good for the implementor of a method because they give her freedom to change the implementation without telling clients. Specifications can make code faster too. Sometimes a weak specification makes it possible to do a much more efficient implementation. In particular, a precondition may rule out certain states in which a method might have been invoked that would have incurred an expensive check that is no longer necessary. 5.2 Contracts, Firewalls, and Decoupling In traditional engineering disciplines, artifacts can often be constructed out of components taken off the shelf. These components are selected on the basis of specifications. This is one crucial role for specification, and indeed it plays this role in software. Unfortunately, however, software components have been largely an unfulfilled aspiration; we have small components (such as string manipulation packages) and huge components (such as relational databases), but very little in between the two. The problem is that medium-sized components seem to be inflexible, and make conflicting assumptions about the structure of the program in which they are embedded. So if you use one of them, you typically can't use another. And of course software is notoriously unreliable, so its specifications often can't be taken too seriously. Some companies are more honest than others about the guarantees they offer: 1Cosmotronic Software Unlimited Inc. does not warrant that the functions contained in the program will meet your requirements or that the operation of the program will be uninterrupted or error-free. However, Cosmotronic Software Unlimited Inc. warrants the diskette(s) on which the program is furnished to be of black color and square shape under normal use for a period of ninety (90) days from the date of purchase. We don't claim Interactive EasyFlow is good for anything ... if you think it is, great, but it's up to you to decide. If Interactive EasyFlow doesn't work: tough. If you lose a million because Interactive EasyFlow messes up, it's you that's out of the million, not us. If you don't like this disclaimer: tough. We reserve the right to do the absolute minimum provided by law, up to and including nothing. This is basically the same disclaimer that comes with all software packages, but ours is in plain English and theirs is in legalese. ACM Software Engineering Notes, Vol. 12, No. 3, 1987. A specification contract imposes obligations on both the client (or user) of the unit specified, and on the implementor of the unit. The contract is understood as an implication: client-meets-obligation => implementor-meets-obligation For example, your contract with the electricity utility places an obligation on you not to exceed a certain load, and an obligation on the utility to provide power at a fixed voltage with only small fluctuations. If you don't exceed the load, and just run an air-conditioner and a handful of lightbulbs, the utility maintains the voltage. But if you decide to run a server farm in your basement that takes a megawatt of power, the utility is not obliged to provide anything. The contract acts as a firewall between client and implementor. It shields the client from the details of the workings of the unit -- you don't need to read the source code of the procedure if you have its specification. And it shields the implementor from the details of the usage of the unit; he doesn't have to ask every client how she plans to use the unit. This firewall results in decoupling, allowing the code of the unit and the code of a client to be changed independently, so long as the changes respect the specification -- each obeying its obligation. Specifications actually play two subtly different roles in software. One is to catalog reusable components: this is the purpose of the specifications in the Java collections framework, for example. The other is to regulate the connections between modules in a design. In this role, a single unit may have multiple specifications, one for each client. The specifications qualify the 'uses' relationship between modules, saying exactly how one module uses another. As the system evolves, these specifications are the part that is least affected. Consequently, perhaps more than anything else, these specifications characterize the design of the software -- they are the design. When we study design patterns, we'll see how the motivation of most design patterns is to improve the decoupling of modules, and this is usually achieved by introducing new specifications, which are weaker than the specifications used in simpler designs. 25.3 Behavioral Equivalence Consider these two methods. Are they the same or different? static int findA (int [] a, int val) { for (int i = 0; i < a.length; i++) { if (a[i] == val) return i; } return a.length; } static int findB (int [] a, int val) { for (int i = a.length -1 ; i > 0; i--) { if (a[i] == val) return i; } return -1; } Of course the code is


View Full Document

MIT 6 170 - Procedure Specifications

Download Procedure Specifications
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view Procedure Specifications and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view Procedure Specifications 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?