1.5: Top Down Design

The purpose of structured programming is to create programs that are

n Understandable, meaning the logic is readily followed

n Reliable, so the program performs as intended

n Adaptable, so modifications can be made with reasonable effort

Structured programming is a method of approaching a problem rather than adhering to a rigid set of rules.

As Dijkstra [1972] observed, the "art of programming is the art of organizing complexity, of mastering multitude and avoiding its bastard chaos as effectively as possible." The essential concept of structured programming is that dealing with complexity requires simplicity.

Regarding terminology, note that the tasks performed by a program solve problems. In this book the words task and problem are used interchangeably. Each programming task entails defining the input information to be processed, defining the output information to be produced, and stating clearly the precise instructions as to what, but not how, it is to be done.

Simplicity and clarity are achieved in a complex program by focusing attention on just one task at a time. To show how the task is done, it is broken down into smaller meaningful subtasks. The combination of smaller tasks to perform the given task is called a refinement of that task. The next step is verifying that the refinement is correct?/FONT>that is, that the refinement indeed accomplishes the task, as long as each of its components does its job. This verification may be done even without knowing how each component works. This is important. How the components of a refinement work is irrelevant to verification. The goal is to ensure that, if they work correctly, then the refinement itself works correctly.

Top-down design begins with the original problem and involves a loop: repeated refining and verifying of the problem and its refinements until only implementable problems remain. Implementable means simple enough to be directly coded in a programming language. Review the development in Section 1.3.2 for primes to see that this loop was, in fact, being used. With this approach the programmer can be sure the final program is correct even though he or she has considered only one manageable piece at a time.

If the total number of tasks needed to complete a detailed solution is proportional to the complexity of the initial problem (as we hope), then the effort to create, understand, and verify a solution to a complex problem will also be proportional to its complexity. This is a very desirable situation. If the cost of a solution increased more drastically with complexity, then the complexity of problems we could solve would be much more severely limited.

Think about building a jigsaw puzzle. You probably use the top-down approach. You break up the picture conceptually into components?/FONT>say, the border and recognizable objects with distinct shapes and colors. Then you build each component and combine them all. Surely the most difficult puzzles are those with no distinguishable objects. They prevent refinement, forcing one to deal with all the complexity at one time. Perhaps this is why all the problems humans solve have structure; they are the only ones we can handle.

Two caveats must be added:

1. At each level of refinement, keep the number of component tasks small and keep them independent. This is critical because human beings can deal well with only a few things at a time, and can do so more readily when the things are not intertwined. Psychological studies suggest a "magic number": a maximum of seven tasks, plus or minus two. Independence means that how one task is accomplished need not be a consideration in how another task is done. Sometimes independence must be given up for other considerations, such as efficiency. These trade-offs should be considered carefully.

2. Control carefully how tasks of a refinement are combined. Simplicity requires structure that makes the logic of a program easily discernible. Certain combinations or constructs foster such clarity. Some programs present a bewildering panorama of program statements, but what is needed are programs that appear as a logical sequence of tasks to be executed. Some ways of expressing the order in which tasks are to be executed are more understandable than others.Constructs that are well designed allow anyone working with a program to grasp quickly what is intended. This is the hallmark of the basic constructs?/FONT>sequence, decision, and loop?/FONT>introduced in Section 1.4.