您的位置:首页 > 运维架构

学习笔记之《Code Reading:The Open Source Perspective》Chapter two(part2)

2010-07-17 20:48 337 查看
Refactoring in the Small

If you have control over a body of code (that is, it is not supplied or maintained by an outside vendor or an open-source group), you can profit by reorganizing code sections to make them more readable. This improvement of the code's design after it has been written is termed refactoring. Start with small changes such as the one we outlined—you can find more than 70 types of refactoring changes described in the relevant literature. Modest changes add up and often expose larger possible improvements.
As a further example, consider the following one-line gem.
 
op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) :
(x == last ? (!y ? upright : (y == bottom ? lowright : right)) :
(!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
[/code]
 

 

The code makes excessive use of the conditional operator ?:. Read expressions using the conditional operator like if code. As an example, read the expression
sign ? -n : n

as follows:
"If sign is true, then the value of the expression is -n; otherwise, the value of the expression is n".
Since we read an expression like an if statement, we can also format it like an if statement; one that uses x ? instead of if (x), parentheses instead of curly braces, and : instead of else.
To reformat the expression, we used the indenting features of our editor in conjunction with its ability to show matching parentheses. You can see the result as follow
op = &(
!x ? (
!y ?
upleft
: ( y == bottom ?
lowleft
:
left
)
) : ( x == last ? (
!y ?
upright
: ( y == bottom ?
lowright
:
right
)
) : (
!y ?
upper
: ( y == bottom ?
lower
:
normal
)
)
))[w->orientation];
[/code]
From Andy:I must say it’s a good way to understand the ternary operator
The expression's intent now becomes clear: the programmer is selecting one of nine different location values based on the combined values of x and y. Both alternative formulations, however, visually emphasize the punctuation at the expense of the semantic content and use an inordinate amount of vertical space.
More advanced Refactoring
 Nevertheless, based on our newly acquired insight, we can create a two-dimensional array containing these location values and index it using offsets we derive from the x and y values. You can see the new result in Figure 1. Notice how in the initialization of the array named locations, we use a two-dimensional textual structure to illustrate the two-dimensional nature of the computation being performed. The initializers are laid out two-dimensionally in the program text, the array is indexed in the normally unconventional order [y][x], and the mapping is to integers "0, 2, 1" rather than the more obvious "0, 1, 2", so as to make the two-dimensional presentation coincide with the semantic meanings of the words upleft, upper, and so on.
Figure 1:
struct options *locations[3][3] = {

{upleft,  upper,  upright},
{left,    normal, right},
{lowleft, lower, lowright},
};
int xlocation, ylocation;

if (x == 0)
xlocation = 0;
else if (x == last)
xlocation = 2;
else
xlocation = 1;

if (y == 0)
ylocation = 0;
else if (y == bottom)
ylocation = 2;
else
ylocation = 1;
op = &(locations[ylocation][xlocation])[w->orientation];
[/code]
The code, at 20 lines, is longer than the original one-liner but still shorter by 7 lines from the one-liner's readable cascading-else representation. In our eyes it appears more readable, self-documenting, and easier to verify. One could argue that the original version would execute faster than the new one. This is based on the fallacy that code readability and efficiency are somehow incompatible. There is no need to sacrifice code readability for efficiency. While it is true that efficient algorithms and certain optimizations can make the code more complicated and therefore more difficult to follow, this does not mean that making the code compact and unreadable will make it more efficient. On our system and compiler the initial and final versions of the code execute at exactly the same speed: 0.6 ms. Even if there were speed differences, the economics behind software maintenance costs, programmer salaries, and CPU performance most of the time favor code readability over efficiency.
Direct and clear expression
But could we somehow directly introduce the two-dimensional structure of our computation into the conditional code? The following code fragment reverts to conditional expressions but has them carefully laid out to express the computation's intent.
op =
&(        !y ? (!x ?  upleft : x!=last ?  upper :  upright) :
y!=bottom ? (!x ?    left : x!=last ? normal :    right) :
(!x ? lowleft : x!=last ?  lower : lowright)
)[w->orientation];
[/code]
The above formulation is a prime example on how sometimes creative code layout can be used to improve code readability. Note that the nine values are right-justified within their three columns, to make them stand out visually and to exploit the repetition of "left" and "right" in their names. Note also that the usual practice of putting spaces around operators is eschewed for the case of != in order to reduce the test expressions to single visual tokens, making the nine data values stand out more. Finally, the fact that the whole expression fits in five lines makes the vertical alignment of the first and last parentheses more effective, making it much easier to see that the basic structure of the entire statement is of the form
op = &(  <conditional-mess>  )[w->orientation];

 

Summary

The choice between the two new alternative representations is largely a matter of taste; however, we probably would not have come up with the second formulation without expressing the code in the initial, more verbose and explicit form.
The expression we rewrote was extremely large and obviously unreadable. Less extreme cases can also benefit from some rewriting. Often you can make an expression more readable by adding whitespace, by breaking it up into smaller parts by means of temporary variables, or by using parentheses to amplify the precedence of certain operators.
You do not always need to change the program structure to make it more readable. Often items that do not affect the program's operation (such as comments, the use of whitespace, and the choice of variable, function, and class names) can affect the program's readability. Consider the work we did to understand the code for the getstops function. A concise comment before the function definition would enhance the program's future readability.
/*

* Parse and verify the tab stop specification pointed to by cp

* setting the global variables nstops and tabstops[].

* Exit the program with an error message on bad specifications.

*/

When reading code under your control, make it a habit to add comments as needed.
 
 
From Andy: Much the same as original article
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息