Structured program design

Structured program design

62.1 Purpose

This chapter discusses the basic principles that underlie structured program design and functional decomposition. The objective of functional decomposition is to design structured programs that are easy to test, debug, and maintain. The basic idea is to break down (or decompose) a program into logically independent modules based on the processes or tasks they perform.

62.2 Strengths, weaknesses, and limitations

Because the detailed computational logic is grouped into independent, single function modules, well-structured programs are easier to test, debug, and maintain than are unstructured programs. Independent modules can be independently coded and tested. The control structure allows the entire program to be tested top down, one module at a time. When an error occurs, it is often possible to quickly isolate the likely cause to a single module. During the maintenance phase, independent modules can be replaced or modified with minimal ripple effects.

Functional decomposition is a process driven methodology. Consequently, although the logic modules are independent, the data are not, and that can lead to ripple effects during testing, debugging, and maintenance.

62.3 Inputs and related ideas

Before starting to design a program using functional decomposition, the necessary logical data structures and the primary processes must be defined during the systems analysis phase (Part IV) of the system development life cycle. Often, the results of analysis are documented in the requirements specification (Chapter 35). Additionally, it is useful to define the physical data structures, file structures, and database structures (Chapters 43, 44, and 45), the required input and output data structures (Chapters 46 through 51), and the algorithms (Chapters 55through 60) before starting program design.

The design of a structured program is sometimes documented using the HIPO technique (Chapter 64). Structure charts (Chapter 63) are useful planning tools. Such tools as logic flowcharts (Chapter 55), Nassi-Shneiderman charts (Chapter 56), decision trees (Chapter 57), decision tables (Chapter 58), pseudocode (Chapter 59), structured English (Chapter 60), and IPO charts (Chapter 64) are used to document the modules.

62.4 Concepts

Functional decomposition is a popular structured program design methodology. The basic idea is to break down (or decompose) a program into logically independent modules based on the processes or tasks they perform.

62.4.1 The control structure

A well-designed structured program consists of a set of independent, single function modules linked by a control structure that resembles a military chain of command or an organization chart (Figure 62.1). Each module is represented by a rectangle. At the top of the control structure is a single module called the root (or the main control module). All control flows from the root which calls (or invokes) its level-2 child (or son) modules. The level-2 modules, in turn, call their level-3 children, and so on. The calling module (sometimes called the parent) passes data and/or control information to the child and receives data and/or control information back from the child; otherwise, the modules are viewed as independent black boxes. Note that control always returns to the calling module.

A module with no children (a lowest-level module) is called a leaf and often implements a single algorithm. Library modules (e.g., a standard subroutine) are indicated by a rectangle marked with two vertical lines; see the leaf labeled Library module in Figure 62.1. Note that a library module can be called by more than one parent.

The modules are often assigned identifying numbers or codes that indicate their relative positions in the hierarchy. For example, the root might be designated module 1.1, the level-2 modules might be designated 2.1, 2.2, 2.3, and so on. Other designers use letters (or even Roman numerals) to designate levels; for example, module A.1 is the root, module B.3 is the third module at level 2, module C.6 is the sixth module at level 3, and so on. Sometimes, more complex numbering schemes are used to indicate a path through the hierarchy. The key is consistency.

62-01
Figure 62.1  A well-designed structured program consists of a set of independent single function modules linked by a control structure.

62.4.2 Designing a control structure

The first step in decomposing a program is to define its high-level control structure. The primary inputs come from the logical models developed during the systems analysis phase (Part IV) and from the requirements specification (Chapter 35). More specifically, the high-level functions to be performed by a given program can often be obtained from the appropriate configuration item’s process description.

62.4.2.1 Afferent, transform, and efferent processes

One approach to designing a control structure is to divide the functions (or subprocesses) into three groups (Figure 62.2). The afferent processes gather and prepare input data. The efferent processes structure and transmit output data. In the middle, the transform processes convert the input data to output form. Identifying the afferent, transform, and efferent processes suggests a basic input, process, output control structure.

62.4.2.2 Trigger events

An alternative is to start with the program’s trigger event, the event that activates the program or causes it to change from a wait to a run state. Some programs are triggered by an asynchronous event such as the arrival of a transaction or an interrupt. Other applications are clock driven; for example, a batch program might be run at the same time every week, and a scientific data collection routine might take a sample every few seconds. A program’s high-level control structure should reference those tasks that are performed in direct response to its trigger event.

62.4.2.3 Data structures

Another technique for designing a high-level control structure is to analyze the data structures. The point of any program is to accept the input data and convert them to the form required for output, so the data actually drive the program design process.

Analyze the output data and determine the order in which the various output substructures are assembled. Then define the input substructures and the algorithms that generate the data elements in a given output substructure. The data structures will, essentially, dictate both the order in which the logical tasks must be performed and the logical structures needed to support those tasks. Generally, sequential data structures call for sequential logic, conditional structures call for conditional logic, and repetitive structures call for repetitive logic.

62-02
Figure 62.2  Afferent, transform, and efferent processes.

62.4.2.4 Logical access maps

Logical access maps were initially proposed by Martin4 to help the designer determine the logical execution sequences or access paths through a program. This technique recognizes that each user (or class of users) has a unique logical accessing perspective. For example, a sales associate might start with a customer order and follow the order through order fulfillment, shipping, and so on. In contrast, warehouse personnel might start with the arrival of a shipment from a supplier, track the shipment into inventory, and view a customer order as nothing more than a transaction that deletes individual items from inventory. The point of logical access mapping is to examine the logical accessing sequence of a system’s programs and a program’s modules from multiple perspectives and to use the consensus view as a design criterion.

62.4.3 Evaluating the control structure

A well-designed control structure exhibits a regular morphology (form, or structure) and achieves a balance between breadth and depth.

62.4.3.1 Morphology

One way to evaluate a control structure’s design is to examine its morphology (form or structure). Each module decomposes into several lower-level routines, so the number of modules should increase from level-2 to level-3, perhaps increase again at level-4, and so on. Eventually, however, only some modules require additional decomposition, so the number of routines at each level begins to stabilize and then to decline.

For example, Figure 62.3 shows a control structure for an inventory management program. Figure 62.4 is a simplified version of the control chart that emphasizes the number of modules at each level. Note the shape; some people describe it as a mosque or a cigar. Most good control structures have a similar shape, with the number of modules at each level increasing, then stabilizing, and then decreasing.

Morphology is subjective; over the years, people have noticed that good designs tend to have that characteristic shape. The designer should not consciously try to make the control structure resemble a mosque. Instead, morphology should be checked after the design is complete. If the shape seems reasonable, the design is probably a good one. If the design deviates significantly from the expected shape, it should be restudied.

62-03
Figure 62.3  A control structure.

62-04
Figure 62.4  The morphology of a good design resembles a mosque or a cigar.

62.4.3.2 Depth and breadth

A well-designed control structure balances two conflicting objectives: depth and breadth. Depth is the number of levels in the control structure. Because each call to a lower level is a potential source of error, shallow structures tend to be better than deep structures. Breadth, or span-of-control, is a measure of the number of modules directly controlled by a higher-level routine. Too many subordinates adds to complexity, so narrow structures tend to be better than broad structures.

Narrow structures are usually deep, so reducing breadth tends to increase depth, and vice versa. One rule-of-thumb for balancing these two parameters suggests that no module should directly control more than seven subordinates. If a given routine has too many subordinate modules, adding a secondary control structure drops some of them to a lower level.

Module size is another useful screen; one page of source code is a common limit. If a module’s logic exceeds roughly 50 lines of code, decompose it. If, on the other hand, the logic in a subordinate routine can be merged into its parent without violating the single page rule, merge it. Remember, however, that rules-of- thumb are not absolute. If breaking one means a better design, break it.

62.4.3.3 Structure clash and boundary clash

Structure clash occurs when corresponding elements of two related data structures are incompatible. For example, imagine that customer social security number is the key for an invoice file and customer zip code is the key for a name and address file. Because the files are (presumably) stored in different record sequences and accessed by different keys, it is difficult to design a program to efficiently merge them.

A boundary clash occurs when the physical data structures are incompatible. For example, if a program sets a nonstandard (9 × 12) page size and the printer is loaded with standard (8.5 × 11) paper, the resulting boundary clash produces poorly aligned output.

Structure clashes and boundary clashes lead to errors and inefficiencies. The program designer should carefully evaluate both the logical and physical data structures and change the program design, the data structures, or both to eliminate structure clash and border clash.

62.4.4 Module design

A good module is cohesive and loosely coupled.

62.4.4.1 Cohesion

Cohesion is a measure of a module’s completeness. Every statement in the module should relate to the same function, and all of that function’s logic should be in the same module. When a module becomes large enough to decompose, each submodule should perform a cohesive subfunction.

The best form of cohesion is called functional cohesion. A functionally cohesive module performs a single logical function, receives and returns no surplus data, and performs only essential logical operations. Functional cohesion is the designer’s objective. A module is not considered function-ally cohesive if it exhibits other forms of cohesion.

Coincidental cohesion is the weakest type. In a coincidentally cohesive module, there is little or no logical justification for grouping the operations; the instructions are related almost by chance. In a logically cohesive module, all the elements are related to the same logical function; for example, all input operations or all data verification operations might be grouped to form a module. The elements that form a temporally cohesive module are related by time; for example, a setup module might hold all operations that must be performed at setup time.

Procedural cohesion is an intermediate form of cohesion, halfway between coincidental cohesion and functional cohesion. All the elements in a procedurally cohesive module are associated with the same procedural unit, such as a loop or a decision structure. Communicational cohesion groups elements that operate on the same set of input or output data (more generally, on the same data structure). With sequential cohesion, the modules form a chain of transformations, with the output from one module serving as input to the next. The three types of cohesion described in this paragraph often result from viewing the program as a flowchart.

62.4.4.2 Coupling

Coupling is a measure of a module’s independence. Perfect independence is impossible because each module must accept data from and return data to its calling routine. Because global data errors can have difficult-to-trace ripple effects, a module should never change the value of any global data element that is not explicitly passed to it. If that rule is enforced, the list of parameters becomes a measure of how tightly the module is linked to the rest of the program. Fewer parameters imply looser coupling.

With data coupling (or input-output coupling), only data move between the modules. Data coupling is necessary if the modules are to communicate. Control coupling involves passing control information (e.g., a switch setting) between the modules. Hybrid coupling is a combination of data coupling and control coupling. For example, if module A modifies an instruction in module B, the operation looks like data coupling to module A and control coupling to module B. Whenever possible, control and hybrid coupling should be eliminated.

With common-environment coupling, two or more modules interact with a common data environment, such as a shared communication region or a shared file. With content coupling, some or all of the contents of one module are included in the other. This problem often occurs when a module is given multiple entry points. Both common-environment and content coupling can lead to severe ripple effects, and should be avoided.

Binding time, the time at which a module’s values and identifiers are fixed, is another factor that influences coupling. A module can be fixed (rendered unchangeable) at coding time, at compilation time, at load time, or at execution time. Generally, the later the binding time the better the module.

62.4.4.3 Sequence, selection, and repetition

The modules that form a well-structured program are composed of three basic logical building blocks or constructs: sequence, selection (or decision), and repetition (or iteration). Go to or branch instructions are not permitted.

Sequence (Figure 62.5) implies that the logic is executed in simple sequence, one block after another. Note that each block might represent one or more actual instructions.

Selection (or decision) logic provides alternate paths through the block depending on a run-time condition. With IF-THEN-ELSE logic (Figure 62.6), if the condition is true the logic associated with the THEN branch is executed and the ELSE block is skipped. If the condition is false the ELSE logic is executed and the THEN logic is skipped. A case structure (Figure 62.7) provides more than two logical paths through the block of logic based (usually) on the value of a control variable.

62-05
Figure 62.5  Sequence.

62-06
Figure 62.6  Selection.

62-07
Figure 62.7  A case structure.

62-08
Figure 62.8  Repetition.

There are two basic patterns for showing repetitive logic: DO WHILE and DO UNTIL (Figure 62.8). In a DO WHILE block, the test is performed first and the associated instructions are performed only if (while) the test condition is true. In a DO UNTIL block, the associated instructions are executed first and then the exit condition is tested.

62.5 Key terms
Afferent process —
A process that gathers and prepares input data.
Binding time —
The time at which a module’s values and identifiers are fixed; for example, coding time, compilation time, load time, or execution time.
Breadth (span-of-control) —
A measure of the number of modules directly controlled by a higher-level routine.
Case structure —
A selection structure with multiple alternative paths; the path through the structure is normally based on the value of a control variable.
Child (son) —
An immediate lower-level module in a control structure. Control passes from the parent to the child and then returns to the parent.
Cohesion —
A measure of a module’s completeness.
Coincidental cohesion —
The weakest type of cohesion in which the elements are related almost by chance.
Common-environment coupling —
A form of coupling in which two or more modules interact with a common data environment, such as a shared communication region or a shared file.
Communicational cohesion —
A form of cohesion that groups elements that operate on the same set of input or output data or on the same data structure.
Configuration item —
A functional primitive; above the configuration level are the system’s logical, composite elements. Below the configuration level are the system’s physical components, including the programs.
Content coupling —
A form of coupling in which some or all of the contents of one module are included in the other.
Control coupling —
A form of coupling in which control information (e.g., a switch setting) is passed between the modules.
Control structure —
A hierarchical model of the flow of control through a program. The control structure resembles a military chain of command or an organization chart. At the top is a main control module that calls secondary control structures. At the bottom are the computational routines, each of which implements a single algorithm.
Coupling —
A measure of a module’s independence; fewer parameters flowing into or out from a module imply looser coupling.
Data coupling (input-output coupling) —
A form of coupling in which only data move between the modules.
Depth —
The number of levels in the control structure.
Efferent process —
A process that structures and/or transmits output data.
Function cohesion —
The strongest type of cohesion in which a given module performs a single logical function, receives and returns no surplus data, and performs only essential logical operations.
Functional decomposition —
A program design methodology in which the program is broken down (or decomposed) into modules based on the processes or tasks they perform.
Hybrid coupling —
A combination of data coupling and control coupling.
Leaf —
A module in a control structure with no lower-level (child) modules.
Logical access map —
A program design tool used to help the designer determine the logical execution sequences or access paths through a program.
Logical cohesion
A form of cohesion in which all the elements are related to the same logical function.
Morphology —
Form or structure.
Procedural cohesion —
A type of cohesion in which all the elements in a module are associated with the same procedural unit, such as a loop or a decision structure.
Repetition (iteration) —
A block of logic that is executed repetitively as long as (while) an initial condition holds or until a terminal condition occurs.
Root —
The module at the top of a control structure from which all control flows.
Selection (decision) —
A block of logic that provides alternate paths through the block depending on a run-time condition.
Sequence —
A block of logic in which the instructions are executed in simple sequence, one after another.
Sequential cohesion —
A form of cohesion in which the modules form a chain of transformations, with the output from one module serving as input to the next.
Span-of-control (breadth) —
A measure of the number of modules directly controlled by a higher-level routine.
Temporal cohesion —
A type of cohesion in which the elements are related by time.
Transform process —
A process that converts the input data to output form.
Trigger event —
The event that activates a program or causes it to change from a wait state to a run state.
62.6 Software

Not applicable.

62.7 References
1.  Davis, W. S., Business Systems Analysis and Design, Wadsworth, Belmont, CA, 1994.
2.  Gane, C. and Sarson, T., Structured Systems Analysis: Tools and Techniques, Prentice-Hall, Englewood Cliffs, NJ, 1979.
3.  Katzan, H. Jr., Systems Design and Documentation: An Introduction to the HIPO Method, Van Nostrand Reinhold, New York, 1976.
4.  Martin J., Information Engineering: Introduction, Vols. 1–3, Prentice-Hall, Englewood Cliffs, NJ, 1990.
5.  Warnier, J.-D., The Logical Construction of Programs, Van Nostrand Reinhold, New York, 1976.
6.  Yourdon, E. and Constantine, Structured Design. Prentice-Hall, Englewood Cliffs, NJ, 1979.

Comments

Popular posts from this blog

The Conversion Cycle:The Traditional Manufacturing Environment

The Revenue Cycle:Manual Systems

Nassi-Shneiderman charts