< Free Open Study > |
This section explains the theory of good layout. The rest of the chapter explains the practice. Layout ExtremesConsider the routine shown in Listing 31-1:
The routine is syntactically correct. It's thoroughly commented and has good variable names and clear logic. If you don't believe that, read it and find a mistake! What the routine doesn't have is good layout. This is an extreme example, headed toward "negative infinity" on the number line of bad-to-good layout. Listing 31-2 is a less extreme example:
This code is the same as Listing 31-1's. Although most people would agree that the code's layout is much better than the first example's, the code is still not very readable. The layout is still crowded and offers no clue to the routine's logical organization. It's at about 0 on the number line of bad-to-good layout. The first example was contrived, but the second one isn't at all uncommon. I've seen programs several thousand lines long with layout at least as bad as this. With no documentation and bad variable names, overall readability was worse than in this example. This code is formatted for the computer; there's no evidence that the author expected the code to be read by humans. Listing 31-3 is an improvement. Listing 31-3. Java layout example #3/* Use the insertion sort technique to sort the "data" array in ascending order. This routine assumes that data[ firstElement ] is not the first element in data and that data[ firstElement-1 ] can be accessed. */ public void InsertionSort( int[] data, int firstElement, int lastElement ) { // Replace element at lower boundary with an element guaranteed to be // first in a sorted list. int lowerBoundary = data[ firstElement-1 ]; data[ firstElement-1 ] = SORT_MIN; /* The elements in positions firstElement through sortBoundary-1 are always sorted. In each pass through the loop, sortBoundary is increased, and the element at the position of the new sortBoundary probably isn't in its sorted place in the array, so it's inserted into the proper place somewhere between firstElement and sortBoundary. */ for ( int sortBoundary = firstElement + 1; sortBoundary <= lastElement; sortBoundary++ ) { int insertVal = data[ sortBoundary ]; int insertPos = sortBoundary; while ( insertVal < data[ insertPos - 1 ] ) { data[ insertPos ] = data[ insertPos - 1 ]; insertPos = insertPos - 1; } data[ insertPos ] = insertVal; } // Replace original lower-boundary element data[ firstElement - 1 ] = lowerBoundary; } This layout of the routine is a strong positive on the number line of bad-to-good layout. The routine is now laid out according to principles that are explained throughout this chapter. The routine has become much more readable, and the effort that has been put into documentation and good variable names is now evident. The variable names were just as good in the earlier examples, but the layout was so poor that they weren't helpful. The only difference between this example and the first two is the use of white space the code and comments are exactly the same. White space is of use only to human readers your computer could interpret any of the three fragments with equal ease. Don't feel bad if you can't do as well as your computer! The Fundamental Theorem of FormattingThe Fundamental Theorem of Formatting says that good visual layout shows the logical structure of a program.
Human and Computer Interpretations of a ProgramLayout is a useful clue to the structure of a program. Whereas the computer might care exclusively about braces or begin and end, a human reader is apt to draw clues from the visual presentation of the code. Consider the code fragment in Listing 31-4, in which the indentation scheme makes it look to a human as if three statements are executed each time the loop is executed.
Listing 31-4. Java example of layout that tells different stories to humans and computers// swap left and right elements for whole array for ( i = 0; i < MAX_ELEMENTS; i++ ) leftElement = left[ i ]; left[ i ] = right[ i ]; right[ i ] = leftElement; If the code has no enclosing braces, the compiler will execute the first statement MAX_ELEMENTS times and the second and third statements one time each. The indentation makes it clear to you and me that the author of the code wanted all three statements to be executed together and intended to put braces around them. That won't be clear to the compiler. Listing 31-5 is another example: Listing 31-5. Another Java example of layout that tells different stories to humans and computersx = 3+4 * 2+7; A human reader of this code would be inclined to interpret the statement to mean that x is assigned the value (3+4) * (2+7), or 63. The computer will ignore the white space and obey the rules of precedence, interpreting the expression as 3 + (4*2) + 7, or 18. The point is that a good layout scheme would make the visual structure of a program match the logical structure, or tell the same story to the human that it tells to the computer. How Much Is Good Layout Worth?
In layout, perhaps more than in any other aspect of programming, the difference between communicating with the computer and communicating with human readers comes into play. The smaller part of the job of programming is writing a program so that the computer can read it; the larger part is writing it so that other humans can read it. Cross-Reference Good layout is one key to readability. For details on the value of readability, see Section 34.3, "Write Programs for People First, Computers Second." In their classic paper "Perception in Chess," Chase and Simon reported on a study that compared the abilities of experts and novices to remember the positions of pieces in chess (1973). When pieces were arranged on the board as they might be during a game, the experts' memories were far superior to the novices'. When the pieces were arranged randomly, there was little difference between the memories of the experts and the novices. The traditional interpretation of this result is that an expert's memory is not inherently better than a novice's but that the expert has a knowledge structure that helps him or her remember particular kinds of information. When new information corresponds to the knowledge structure in this case, the sensible placement of chess pieces the expert can remember it easily. When new information doesn't correspond to a knowledge structure the chess pieces are randomly positioned the expert can't remember it any better than the novice. A few years later, Ben Shneiderman duplicated Chase and Simon's results in the computer-programming arena and reported his results in a paper called "Exploratory Experiments in Programmer Behavior" (1976). Shneiderman found that when program statements were arranged in a sensible order, experts were able to remember them better than novices. When statements were shuffled, the experts' superiority was reduced. Shneiderman's results have been confirmed in other studies (McKeithen et al. 1981, Soloway and Ehrlich 1984). The basic concept has also been confirmed in the games Go and bridge and in electronics, music, and physics (McKeithen et al. 1981). After I published the first edition of this book, Hank, one of the programmers who reviewed the manuscript, said "I was surprised that you didn't argue more strongly in favor of a brace style that looks like this: for ( ...) { } "I was surprised that you even included the brace style that looked like this: for ( ...) { } "I thought that, with both Tony and me arguing for the first style, you'd prefer that." I responded, "You mean you were arguing for the first style, and Tony was arguing for the second style, don't you? Tony argued for the second style, not the first." Hank responded, "That's funny. The last project Tony and I worked on together, I preferred style #2, and Tony preferred style #1. We spent the whole project arguing about which style was best. I guess we talked one another into preferring each other's styles!"
Layout as ReligionThe importance to comprehension and memory of structuring one's environment in a familiar way has led some researchers to hypothesize that layout might harm an expert's ability to read a program if the layout is different from the scheme the expert uses (Sheil 1981, Soloway and Ehrlich 1984). That possibility, compounded by the fact that layout is an aesthetic as well as a logical exercise, means that debates about program formatting often sound more like religious wars than philosophical discussions. At a coarse level, it's clear that some forms of layout are better than others. The successively better layouts of the same code at the beginning of this chapter made that evident. This book won't steer clear of the finer points of layout just because they're controversial. Good programmers should be open-minded about their layout practices and accept practices proven to be better than the ones they're used to, even if adjusting to a new method results in some initial discomfort. Cross-Reference If you're mixing software and religion, you might read Section 34.9, "Thou Shalt Rend Software and Religion Asunder" before reading the rest of this chapter. Objectives of Good LayoutMany decisions about layout details are a matter of subjective aesthetics; often, you can accomplish the same goal in many ways. You can make debates about subjective issues less subjective if you explicitly specify the criteria for your preferences. Explicitly, then, a good layout scheme should do the following:
Accurately represent the logical structure of the code That's the Fundamental Theorem of Formatting again: the primary purpose of good layout is to show the logical structure of the code. Typically, programmers use indentation and other white space to show the logical structure. Consistently represent the logical structure of the code Some styles of layout have rules with so many exceptions that it's hard to follow the rules consistently. A good style applies to most cases. Improve readability An indentation strategy that's logical but that makes the code harder to read is useless. A layout scheme that calls for spaces only where they are required by the compiler is logical but not readable. A good layout scheme makes code easier to read. Withstand modifications The best layout schemes hold up well under code modification. Modifying one line of code shouldn't require modifying several others. In addition to these criteria, minimizing the number of lines of code needed to implement a simple statement or block is also sometimes considered. How to Put the Layout Objectives to Use
Weighting the criteria in different ways might lead to different conclusions. For example, if you feel strongly that minimizing the number of lines used on the screen is important perhaps because you have a small computer screen you might criticize one style because it uses two more lines for a routine parameter list than another. |
< Free Open Study > |