31.1. Layout Fundamentals

 < Free Open Study > 

This section explains the theory of good layout. The rest of the chapter explains the practice.

Layout Extremes

Consider the routine shown in Listing 31-1:

Listing 31-1: Java layout example #1

/* 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; }


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:

Listing 31-2: Java layout example #2

/* 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 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 Formatting

The Fundamental Theorem of Formatting says that good visual layout shows the logical structure of a program.

Making the code look pretty is worth something, but it's worth less than showing the code's structure. If one technique shows the structure better and another looks better, use the one that shows the structure better. This chapter presents numerous examples of formatting styles that look good but that misrepresent the code's logical organization. In practice, prioritizing logical representation usually doesn't create ugly code unless the logic of the code is ugly. Techniques that make good code look good and bad code look bad are more useful than techniques that make all code look good.


Human and Computer Interpretations of a Program

Layout 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.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Martin Fowler

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 computers
  x = 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?

Our studies support the claim that knowledge of programming plans and rules of programming discourse can have a significant impact on program comprehension. In their book called [The] Elements of [Programming] Style, Kernighan and Plauger also identify what we would call discourse rules. Our empirical results put teeth into these rules: It is not merely a matter of aesthetics that programs should be written in a particular style. Rather there is a psychological basis for writing programs in a conventional manner: programmers have strong expectations that other programmers will follow these discourse rules. If the rules are violated, then the utility afforded by the expectations that programmers have built up over time is effectively nullified. The results from the experiments with novice and advanced student programmers and with professional programmers described in this paper provide clear support for these claims.

Elliot Soloway and Kate Ehrlich

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!"

This experience, as well as the studies cited above, suggest that structure helps experts to perceive, comprehend, and remember important features of programs. Expert programmers often cling to their own styles tenaciously, even when they're vastly different from other styles used by other expert programmers. The bottom line is that the details of a specific method of structuring a program are much less important than the fact that the program is structured consistently.


Layout as Religion

The 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 Layout

Many 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:

The results point out the fragility of programming expertise: advanced programmers have strong expectations about what programs should look like, and when those expectations are violated in seemingly innocuous ways their performance drops drastically.

Elliot Soloway and Kate Ehrlich

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

You can use the criteria for a good layout scheme to ground a discussion of layout so that the subjective reasons for preferring one style over another are brought into the open.


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 > 


Code Complete
Code Complete: A Practical Handbook of Software Construction, Second Edition
ISBN: 0735619670
EAN: 2147483647
Year: 2003
Pages: 334

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net