• No results found

39 A module passes (sends) data to another module and then that module returns data For example, a

program may pass numbers to a subroutine that will return their sum. Interface specifications describe the variables passed to and from modules.

Yourdon (1975) is a good introduction to logic design and structural design. After Yourdon, read Yourdon & Constantine (1979).

Data design

The designer asks the following questions:

• What are the data and what data structures are appropriate to hold them? Related data should be organized in a way that leaves the relationships clear. Different types of relationships are best expressed by different data structures. Examples of data structures are simple variables, arrays, records, stacks, queues, linked lists, and trees. Elson's (1975) introduction to these is quite readable. • Which routines need access to a given set of data? Should these data be stored

globally, in memory or on disk, accessible to any routine that asks for it, or should one routine own the data and pass copies to others on request? Which routines are allowed to change these data? How is it ensured that only these routines can change them? How are these restrictions made obvious to someone reading or modifying the code?

• How should the data be named? Are there naming conventions? Can a maintenance programmer understand the function of each variable from the name?

• What about data storage? Some data will be stored (e.g., on disk) and retrieved lateT. How should they be stored? How should they be organized on disk? How should they be retrieved? (See Part II of Martin & McClure (1983) for a good introductory discussion of these issues.)

Implicit in the discussion of structural design was the view that a product should be primarly analyzed in terms of its functions. Under this perspective, a module is characterized by what it does; analysis of its data is secondary.

Realize, though, that two modules that operate on the same data are closely related, even if they do different things to the data for different purposes. For example, if the data structure changes, both modules must be recoded.

It's useful to stand the function-oriented approach on its head, conceptualizing the program from the point of view of the data. From this perspective, a program is something that transforms data, in stages, from initial input, through various intermediate results, to final output (such as a report). Modules are considered incidentally, and only in terms of their effect on the data: this module needs that information as input, expects that these data were entered or calculated already, and will produce these outputs. A module is characterized by a description of its inputs and outputs; its "function" is implicit in this description. Such an analysis can expose a variety of natural, and sometimes inescapable, relationships between what might otherwise be considered different pieces of a program. Overall design and decomposition might take advantage of these relationships, defend against consequences of them, or passively reflect them as a natural approach to decomposition of the program's tasks.

For a good introductory comparison of different design approaches, see Bergland (1981). Gane & Sarson (1979) is an excellent introduction to data design. For further discussion of data flow and relationships between modules, begin with DeMarco (1979), then read Yourdon & Constantine (1979). To follow up on data-oriented testing approaches, read Beizer (1990).

40

DESIGN STAGES INTERNAL DESIGN

Logic design

Logic design

Design doesn't end with the specification of a module's task and data. Someone (usually the programmer) still has to figure out how to do the task. This may include choosing an "optimal" algorithm. It includes outlining the logical steps involved in the task, often in progressively greater detail.

Yourdon (1975) is a good source on the process of translating a high level design and into working code.

P

ROTOTYPING

A prototype is a model of the system or of part of it. The prototype is built as quickly and cheaply as possible.

It should be easy and cheap to change. It does not have to do any "real" work. Its function is to give the people who work with it an inexpensive, direct experience of one way that the product can work.

Some prototyping is done in the service of internal design. In a top-down design process, the system is broken into a few higher order processes or modules, which are in turn broken into modules, which are then broken down further. Each higher order module is coded before the modules it calls are coded. Sometimes, though, the design depends on assumptions about the lowest level routines. Suppose the design of a module requires a particular low level interrupt handling routine to execute and exit within 60 microseconds. It is only prudent to model this routine early, and make sure it can meet its requirements. Otherwise the other modules (in some real cases, the whole system) will have to be redesigned.

Prototyping is most often done to explore and evaluate the functionality and user interface of the system. This is essential: once people get a chance to play with the system, or with a model of it, their requirements change. Ideas that seemed reasonable or even good when they were written in a specification look less good in a working model (Martin & McClure, 1983; Wasserman & Shewmake, 1985).

Martin & McClure (1983) strongly recommend that functionality and user interface prototypes be written in the language of the final product. If the prototype works well, they say it should become the final product. With rare exceptions, we think this is bad advice because:

• Many development languages are not suited to rapid, cheap prototyping.

• This notion flies in the face of good advice from Brooks (1975) and Kernighan & Plauger (1974). They recommend throwing away the first draft of any program. Their recommendation is especially applicable to prototypes. A prototype doesn't have to be well designed internally. It needn't always work. It can be slow and inefficient. As long as it gives the user a feel for the product, it's OK. We don't want this as production code. Designers need the freedom to write bad code quickly that models a system well, and then throw that code away.

DeGrace & Stahl (1990), Helander (1991, Chapter 39), Rubenstein & Hersh (1984), Ould (1990), and Schneiderman (1987) discuss user interface prototyping, evaluation strategies, and techniques.

41