Software Engineering For Students: A Programming Approach Part 12 pps

10 353 0
Software Engineering For Students: A Programming Approach Part 12 pps

Đang tải... (xem toàn văn)

Thông tin tài liệu

88 Chapter 7 ■ Structured programming One view of structured programming is that it holds that programs should only be built from three components: sequences (normally written in the order in which the statements are to be executed), selections (normally written as if-then-else), and repetitions (written as while-do). The goto statement is, by implication, banned. In this chapter we begin by examining the controversy about the goto statement. The outcome of the argument is that gotos are an irrelevancy; the argument is about some- thing else, good program structure. We go on to explore the significant principles of structured programming. There are some other principles. We will explore these using flowcharts, which describe flow of control. A flowchart is read from the top downwards or in the direc- tion of the arrows. Flowchart decisions (corresponding to if or while statements in code) are drawn as diamonds. Flowchart activities are shown as rectangular boxes. A flowchart is very similar to a UML activity diagram and conveys the same information. If the three structures of structured programming are diagrammed as flowcharts (Figure 7.1), the following characteristics become clear: 1. they have only one entry and exit 2. none of the constructs consists of more than three boxes Figure 7.1 The three structures of structured programming Figure 7.2 A control structure that is not structured BELL_C07.QXD 1/30/05 4:19 PM Page 88 7.2 Arguments against goto 89 If we visualize any one of the three constructs as they are used, then a third character- istic is evident: 3. the entry is at the start and the exit is at the end. Why is it that these characteristics are important? Why are other constructs that have the same characteristics (Figure 7.2) ruled out? We now go on to look at these questions. SELF-TEST QUESTION 7.1 Write a loop that repeats ten times, first using a while statement, then using goto. gotos are unnecessary Fortunately there is a mathematical theorem (thanks to Bohm and Jacopini) guaran- teeing that any program written using goto statements can be transformed into an equivalent program that uses only the structured constructs (sequence, selection and iteration). The converted program will, in general, need additional data items that are used as flags to control the actions of the program. Indeed the new program may look rather contrived; nonetheless, it can be done. On the face of it, therefore, there is no need for programs with gotos in them. Note, as an interesting side issue, that the theorem does not tell us how to transform the unstructured program; only that it can be done. Experimental evidence Structured programming is well established and widely regarded as the best approach to programming. You might think, therefore, that there would be clear evidence from real software projects that it is beneficial, but this is not so; there are no convincing results from real projects, largely because a carefully controlled experiment would be difficult and expensive to mount. It would be necessary to develop a particular piece of software in two ways: once using structured programming and again using “unstruc- tured” programming. All other variables, like the expertise of the programmers, would have to be held constant. The two versions of the software could be compared accord- ing to criteria like development time and number of errors. Regrettably, there are no results of this type. However, experimenters have carried out small-scale studies comparing how easily people can understand and debug small structured programs compared with unstruc- tured ones. In a typical experiment, each of a group of subjects is presented with the 7.2 ● Arguments against goto BELL_C07.QXD 1/30/05 4:19 PM Page 89 listing of a program that is written in a structured way and asked a series of questions that are designed to assess their comprehension of it. The accuracy of the replies and the time taken to reply are both measured. These are measures of the ease with which the program could be debugged or changed. A second group of subjects are given copies of the same program rewritten in an unstructured way. The accuracy and response times of the two groups are compared. The results of these experiments gen- erally indicate that structured programs are superior to unstructured ones. The results of empirical studies are reviewed in the literature given at the end of the chapter. In a review published in 1984, long after the dust had settled on the structured programming debate, Vessey and Weber concluded that “the evidence supporting [structured programming] is weak”. This conclusion largely stems from the difficulty of carrying out experiments that give trustworthy results. Clarity and expressive power Compare the following two equivalent program fragments: label: while a > 0 if a > 0 goto label endwhile As we read down the first program fragment, we are not immediately sure what the roles of the label and goto are. It would take us some time to read and study the pro- gram in order to discover that they are being used to create the repetition of a piece of code. This is made immediately obvious by the while statement in the second pro- gram. Worse, there is a remaining doubt in the first program that there may be another goto aimed at this same label from some other point in the program. The facilities of a programming language should allow people to describe what they want to do in a meaningful way. If we examine a typical program written using gotos we see that the gotos are used for a variety of purposes, for example: ■ to avoid a piece of code (which is to be executed in different circumstances) ■ to perform repetition ■ to exit from the middle of a loop ■ to invoke a shared piece of code. When we see a goto, there are few clues that allow us to decide the purpose for which the goto is being used. The alternative is, of course, a unique language con- struct for use in each of these different circumstances. These are, respectively: 90 Chapter 7 ■ Structured programming > > BELL_C07.QXD 1/30/05 4:19 PM Page 90 7.2 Arguments against goto 91 ■ if-then-else ■ while-do or repeat-until ■ exit ■ method call It is as if the goto is too primitive an instruction – like a machine instruction to load a register – that can be used in a whole variety of circumstances, but does not clearly convey its meaning in any of them. In summary, the goto lacks expressive power and it is therefore difficult to under- stand the logic of a program that is written using a lot of gotos. When we look at a piece of coding, words like while and if give us a strong clue as to what is intended; gotos do not. How many pencils? Suppose we want to read a program in order to understand it by tracing through it as if we were a computer executing it. Suppose we have available a supply of pencils (or fingers) to help us. The pencils will be used as markers, and are to be placed on the pro- gram listing to point to places of interest. If we are following a simple sequence, then we will only need one pencil to keep track of our position. If we encounter a method call, we need two pencils, one to leave at the point of the call (in order to know where to return) and another to proceed into the method. If we encounter a while statement or a for loop, then we need an integer, a counter, to keep count of the number of times we have repeated the loop. To summarize, if the program has been written in a structured way, we need: ■ one pencil to point to the current position ■ one pencil to point to each method call that has been executed but not returned from ■ a counter for every uncompleted loop. This may seem like a lot of equipment, but consider the alternative of a program that contains a lot of gotos. As before, we will need to indicate the position of the current statement. Next, we need a pencil to point at every goto that has been executed. But now, whereas in the structured program we can remove a pencil whenever we return from a method, finish a loop or complete an if statement, we can never dispense with pencils; instead we need ever more. The increased number of pencils reflects the increased complexity of the goto program. The real problem becomes evident when we want to refresh our memory about what happened before we arrived at the current point in the program. In the program with- out gotos we simply look back up the program text. In the unstructured program, when we look backwards we are defeated as soon as we reach a label, because we have no way of knowing how we reached it. BELL_C07.QXD 1/30/05 4:19 PM Page 91 92 Chapter 7 ■ Structured programming Ease of reading (static and dynamic structures) In the Western world we are used to reading left to right and top to bottom. To have to begin by reading forwards and then to have to go backwards in the text is rather unnatural; it is simpler if we can always continue onwards. It is an important feature of a structured pro- gram that it can always be read from top to bottom – provided it has no methods. The excep- tion to this rule arises in comprehending a while loop, during which repeated references back to the terminating condition at the start of the loop are necessary. Programs are essentially dynamic beings that exhibit a flow of control, while the pro- gram listing is a static piece of text. To ease understanding, the problem is to bring the two into harmony – to have the static text closely reflect the dynamic execution. In a structured program, the flow of control is always down the page, which exactly corre- sponds to the way that text is normally read. Proving programs correct Formally to prove all programs correct is not a practical proposition with present-day techniques. Nonetheless there are some lessons that can be learned from proving. In one technique of program proving, assertions are made at strategic points in the program. An assertion is a statement of what things are true at that point in the pro- gram. More exactly, an assertion describes the relationships that hold between data items that the program acts upon. Assertions at the start and end of a piece of program are called the input and output assertions respectively. Proving consists of rigorously demonstrating that if the input assertion is true, then the action of the program will lead to the output assertion being true. A structured program consists solely of components that have a single entry and a single exit point. This considerably aids the process of reasoning about the effect of the program. In contrast, it is usually impossible to isolate single-entry, single-exit struc- tures within a program with gotos in it. Even when formal proof techniques are not being used, but where an informal study of the program is being made, the single-entry and single-exit character of programs aids checking and understanding. Deskilling The goto statement is one tool among many provided by the programming language. To take it away from the programmer is to deprive him or her of a tool that can be validly used in certain circumstances. Consider a craftsperson who is an expert at making delicate objects from wood. Suppose that we remove from that person a tool that we consider to be inappropriate, say an ax. The skill of making a discriminating selection among the available tools is reduced, because the choice is narrower. Furthermore, the skill in using the tool is no 7.3 ● Arguments in favor of goto BELL_C07.QXD 1/30/05 4:19 PM Page 92 7.3 Arguments in favor of goto 93 longer required. (Remember, however, that there may occasionally be circumstances in which an ax is the most suitable tool.) Exceptions Often a program is required to detect an error and to take some special action to deal with it. Suppose that such an error is detected many levels down in a chain of method calls. One way of handling the error is to create an additional parameter associated with each method call. This approach can become very unwieldy as methods receive and merely pass on parameters that they do not need to act on. An alternative is for the method detecting the error to simply goto a suitable place in the program where the error can be dealt with. This can result in a significant sim- plification to the program. The essence of the argument is that an exceptional situation in the program demands an exceptional solution – a goto. Some programming languages, such as Java, have solved this problem using a special mechanism for handling exceptional situations. Program performance On occasions it is possible to write a program that will run more quickly using goto statements. An example is a program to search an array a for an item x: for i = 1 to tableSize if a[i] = x then goto found endif endfor notfound: found: The nearest we can get to writing this as a structured program is to write: i = 1 while i <= tableSize and a[i] not = x i = i+1 endwhile if i > m then else > > > BELL_C07.QXD 1/30/05 4:19 PM Page 93 94 Chapter 7 ■ Structured programming endif which requires an additional test. Although both programs achieve the same end – finding (or not finding) the desired item – the steps taken by the two programs differ. The first (unstructured) program takes fewer steps, and there is no way of writing a structured pro- gram that works in the same way. Thus it is possible to write goto programs that run more quickly than structured ones. Naturalness Consider the table searching program above. Arguably the unstructured solution is the best in the sense that it is the solution that solves the problem most naturally. Any trans- formation of this program, or any other solution, is a distortion of the natural solution. In other words, getting rid of gotos in existing programs (as can always be done), will sometimes needlessly destroy a good program. The trouble is deciding what is natural. It surely differs from person to person, depending on individual psychology and cultural experiences. So it is a rather subjec- tive judgment. Rather than take part in a parochial debate about the merits of a particular control structure, let us take a constructive approach. If we had a free choice and a blank piece of paper, what control structures would we choose to use in programming? Perhaps our first consideration should be to establish the principles that govern the selection. Let us examine the following criteria: ■ standardization ■ abstraction ■ expressive power ■ orthogonality ■ minimality. We shall see that some of these conflict with each other. Note also that in our examin- ation we are confining ourselves to sequential, imperative programming, in contrast to concurrent or declarative programming (as in logic or functional programming). Standardization Domestic appliances exhibit enormous variety and yet all plug into a standard socket. Similarly, it is desirable to build software from components that all exhibit the same external interface. 7.4 ● Selecting control structures > BELL_C07.QXD 1/30/05 4:19 PM Page 94 7.4 Selecting control structures 95 The simplest interface comprises one entry point, at the start, and one exit point at the end. This has the strength of being consistent with the essence of sequential pro- gramming. It also conforms to the important idea of calling a method. We are used to the idea of calling a method as a sequential step and returning from it to the next instruction in sequence. (We do not, for example, expect to supply a label as a param- eter to which control is returned.) Abstraction This is probably the most important idea in structured programming. The human mind cannot devise or understand the whole of a complex system. Instead we can only under- stand one part of the system at a time. Nonetheless it is vital to understand the whole system. The only way to resolve these contradictory statements is to be able to perceive the overall structure in a digestible way. The solution is to use abstraction, that is, the system must be described in a notation that allows subsystems to be seen as black boxes whose task is readily understood but whose detail is invisible. In programming, the method has long been a mechanism that fulfills this role. Other constructs that possess the same single-entry at the start, single-exit at the end property, are if-then-else and while-do. Expressive power In discussing the arguments against the goto statement, we saw that the goto is too primitive. It has more to do with describing what a machine will do than what a pro- grammer intends. Instead we look at the range of structures on offer, tempted on the one hand to seize every mechanism available, while at the same time conscious of the need for minimality. Certainly we need some mechanism for repetition, and either a while statement or recursion is sufficient to provide this facility. Many languages provide both a while statement and a repeat-until statement. Most languages also support recursion. Arguably we also require a statement to carry out a choice of actions following a test. The if-then-else fulfills this requirement, but others are equally valid, including the case statement. Again, we are torn between expressive power and minimality. Orthogonality When designing a set of facilities, a good design principle is to create features that are each as different from each other as possible. If this is so, we can more easily satisfy the goal of a minimum number of functions, while at the same time ensuring that the facil- ities are sufficiently powerful for all our needs. Minimality The principle of minimality curbs our tendency to include too many facilities. A conse- quence of Bohm and Jacopini’s theorem is that we know that the three control structures BELL_C07.QXD 1/30/05 4:19 PM Page 95 96 Chapter 7 ■ Structured programming (sequence, selection and iteration) are sufficient. (Strictly, a construct for iteration, such as a while, is also unnecessary, because any loop that can be written iteratively can also, in theory, be achieved using only recursion.) Consider the flowcharts of various control structures. Sequence has one box, while has two, and if has three boxes. There are other control structures that involve only three or less boxes; but from amongst them all, these are the minimal feasible set. It is easy to become engrossed in the arguments about the goto statement, but is this the central issue of structured programming? Can a program that is written using only the three structures claim to be well struc- tured? The answer is no; it is possible to create a bad program structure using the three structures, just as it is possible (with greater difficulty) to create a good structure that uses goto statements. To illustrate why this is so, consider a badly structured program that has been written using many gotos. If we now transform this into a program that uses the three structures, we still have a badly structured program, since we have done nothing significant to improve it. As a second example, consider a program to search a table for a required item. Two alternative solutions, one structured, the other not, were compared earlier. However, arguably, neither of these is the best solution. Here is another, in which the item being sought is first placed at the end of the table: a[tableSize + 1] = x i = 1 while a[i] not = x i = i + 1 endwhile if i = tableSize + 1 then else endif This is arguably the best of the solutions because it is less complex (the condition in the while statement is simpler) and would execute more quickly on a conventional computer (for the same reason that there is only one condition to test). This example illustrates that the use of the approved structures does not necessarily guarantee the best design. A structured program is essentially one that can be understood easily, and the most useful tool in understanding is abstraction. Abstraction is concerned with identifying the major elements of what is being studied, and ignoring detail. Such is the complex- ity of software that we have to do this in order to stand a chance of understanding it. 7.5 ● What is structured programming? > > BELL_C07.QXD 1/30/05 4:19 PM Page 96 7.5 What is structured programming? 97 Abstraction can only be achieved if the control flow constructs are used in a disci- plined way, so that part of structured programming is the avoidance of gotos. For example, consider the program in Figure 7.3. We can draw boxes around components as shown. Because it is built from limited control structures, we can view the program at all levels of detail as consisting of abstract components that have only one entry and one exit. If we examine any subsys- tem of the program, it is totally contained – the boxes do not overlap. If we look in detail at its contents, it does not suddenly sprout connections with other subsystems. When we uncover the nested contents of a traditional Russian wooden doll, we do not expect suddenly to encounter a doll that affects any of those we have already seen. (Structured programs are, of course, more complex than these dolls; it is as if, when we open a doll, not just one, but several more are revealed.) Suppose that in the above program we inserted a goto as shown in Figure 7.4. We have now ruined the structure, since we can no longer view the program at different levels of abstraction. As an analogy compare the problems of understanding a plate of spaghetti as com- pared with a plate of lasagna. In order to understand the spaghetti, we have to under- stand it all; we cannot employ abstraction. With the lasagna, we can peel off layers, one by one, uncovering the interesting detail of successive layers and understanding each separately from the others. while do if then else endif endWhile if then endif Figure 7.3 A structured program, showing self-contained components BELL_C07.QXD 1/30/05 4:19 PM Page 97 . judgment. Rather than take part in a parochial debate about the merits of a particular control structure, let us take a constructive approach. If we had a free choice and a blank piece of paper, what. program demands an exceptional solution – a goto. Some programming languages, such as Java, have solved this problem using a special mechanism for handling exceptional situations. Program performance On. additional parameter associated with each method call. This approach can become very unwieldy as methods receive and merely pass on parameters that they do not need to act on. An alternative is for

Ngày đăng: 03/07/2014, 01:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan