您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

25KB

The Psychology of Computer Programming — Chapter-01: Reading Programs

  • Source: /library/The Psychology of Computer Programming/source-file.pdf
  • PDF pages: 31–42
  • Pages without text: none
  • Note: Includes the Silver Anniversary comments that immediately follow the original chapter. Text comes from the scan's OCR layer and may contain recognition errors.

| READING PROGRAMS ome years ago, when COBOL was the great white programming hope, one heard much talk of the possibility of executives being able to read programs. With the perspective of time, we can see that this claim was merely intended to attract the funds of executives who hoped to free themselves from bondage to their pro- grammers. Nobody can seriously have believed that executives could read programs. Why should they? Even programmers do not read pro- grams. But isn’t it quite proper that only the machine should read programs? Weren't the programs written for the machine? Yes and no. Even if we were not concerned with program modification and with the interfaces between programs, reading programs might not be such a bad idea from the point of view of learning about programming. Programming is, among other things, a kind of writing. One way to 5

6 Programming as Human Performance learn writing is to write, but in all other forms of writing, one also reads. We read examples—both good and bad—to facilitate learning. But how many programmers learn to write programs by reading programs? A few, but not many. And with the advent of terminals, things are getting worse, for the programmer may not even see his own program in a form suitable for reading. In the old days—which in computing is not so long ago—we had less easy access to machines and couldn’t afford to wait for learning from actual machine runs. Turnaround was often so bad that programmers would while away the time by reading each others’ pro- grams. Some even went so far as to read programs from the program library—which in those days was still a library in the old sense of the term. But, alas, times change. Just as television has turned the heads of the young from the old-fashioned joys of book reading, so have terminals and generally improved turnaround made the reading of programs the mark of a hopelessly old-fashioned programmer. Late at night, when the grizzled old-timer is curled up in bed with a sexy subroutine or a mystify- ing macro, the young blade is busily engaged in a dialogue with his terminal. No doubt it is much more thrilling to be face to face with the giant computer than merely wrapped in quiet contemplation of the work of others. But is it more edifying? A young novelist of our time was recently asked who were his favorite authors. He responded simply that he never read novels, as his ideas were so new and superior to anyone else’s that reading would only be a waste of his time. As you might expect, his work did not support his thesis. Perhaps the same could be said for some of our radical young Programmers. Perhaps there is something to be gained from reading other people’s programs—if only the amusement engendered by their bad examples. Perhaps if we want to understand how programmers program —to lift the veil of the programming mystique—we could fruitfully uegip by seeing what is to be learned from the reading of programs. AN EXAMPLE In order to illustrate the joys and fruits of program reading, let us take a tiny example gleaned from a professional lifetime of program reading— one small program from among thousands. Suppose then that we come across the PL/I program shown in Figure 1-1. What are we to make of it? We shall need a method of approach for reading programs, for, unlike novels, the best way to read them is not always from beginning to end. They are not even like mysteries, where we can turn to the penultimate

Reading Programs 7 XXX: PROCEDURE OPTIONS(MAIN); DECLARE 8(1000) FIXEN(7,2), C FIXED(11,2), (1, J) FIXED BINARY; Cini): DOT har ih TN 718; GET LIST((B(J) DO J = 1 TO 1N00)); DO J = 1 TO 1000; C's Ce BC) END; PUT LIST(‘SUM IS ‘, C); END XXX; Figure 1-1 A program to be read. page for the best part—or like sexy books, which we can let fall open to the most creased pages in order to find the warmest passages. No, the good parts of a program are not found in any necessary places— although we will later see how we can discover crucial sections for such tasks as debugging and optimization. Instead, we might base our reading on a conceptual framework consisting of the origin of each part. In other words, as we look at each piece of code, we ask ourselves the question, “Why is this piece here?” MACHINE LIMITATIONS One of the reasons which account for pieces of code is that the ma- chine on which the program is to be run is limited in some way relative to the ideal machine for the problem. In our example, we see that a total of 10,000 numbers are read into the computer and summed, but they are read in batches of 1000. As the numbers are evidently punched in PL/I LIST format, there is no reason why this division should be made, unless perhaps the total storage was limited so that all 10,000 numbers could not be stored at once. In other words, not having 40,000 bytes available,

8 Programming as Human Performance the programmer had to break up his summing into smaller sections, which led to the inclusion of an extra loop. If he had been able to store all 10,000 numbers, he might have written the program as shown in Figure 1-2. Of course, when the programmer includes something that is intended to overcome some limitation of the machine, he rarely marks it explicitly as such. Although this omission adds to the intrigue of reading programs, it does penalize the program when, for example, it is transferred to an- other machine. The programmer may not even be aware that some of his coding is intended to compensate for a limitation of the machine, in which case he could hardly be expected to mark it. For instance, much programming has to be done to overcome the limited precision of our machines—or better still, the fact that they do not calculate with real numbers but only with a limited set of the rationals. Yet programmers tend to forget that these are limitations of the hardware and come to think of them as facts of life. When we include such words as REAL in Our programming languages, we compound the difficulty, and make it less likely that machine designers will become aware of the difficulties this difference causes programmers. Another area in which machine limitations are rife is intermediate Storage. In the first place, we wouldn’t have intermediate storage at all if we knew how to build the right kind of primary storage devices cheaply enough. But short of that Nirvana, we still have to contend with a plethora of drums, disks, tapes, and the like—all of which lead to enormous XXX: PROCEDURE OPTIONS(MAIN); DECLARE A(10000) FIXEN(7,2), CUPIXEDCII, 2), J FIXED BINARY; GET LISTC(ACJ) DO J = 1 TO 10000)); DO J = 1 TO 10000; C=C

  • ACJ); END; PUT LISTC'SUM IS ‘, C); END XXX; Figure 1-2 Storage limitation removed.

Reading Programs 9 amounts of coding. Moreover, each device has peculiar timing character- istics, modes of addressing, and storage capacity, and we find much programming devoted to overcoming the less-than-optimum (from the programmer’s point of view) configuration we happen to have. LANGUAGE LIMITATIONS But machine limitations are not our primary concern here, for we are seeking the human underpinnings of programming. A step closer to these underpinnings is the programming language—assuming that nobody— but nobody—programs in machine language anymore. One of the con- sequences of moving up above machine language is that certain facilities of the hardware may be lost to the user. An example of this type is the end-of-file situation which exists in some FORTRAN systems. In these systems, the machine is perfectly able to recognize an end-of-file and pass control to another section of the program, but the FORTRAN lan- guage provides no such facility. Thus, the programmer has to resort to devices such as the ‘‘end-of-file card”—an example in which both the coding and the data have to be modified to overcome language limitations. In our example, the language limitation is more subtle. PL/I provides the programmer with a built-in function called SUM for taking the sum of the elements of an array. In the original definition of the language, however, at the time this program was written, SUM was a so-called “mathematical” function, rather than an “arithmetic” function. What this meant was that it assumed floating point input—and converted its input to floating point if necessary. Aside from questions of efficiency, this conversion could mean the loss of precision if the array—as in this ex- ample—consisted of FIXED DECIMAL numbers with fractional parts. Many programmers were distressed to discover that pennies were being lost when they tried to balance accounts using SUM. The resulting protest led to a redefinition of SUM as arithmetic generic, but, in the meantime, it could not be used successfully on a problem such as our example. Without this language limitation, the program could have been shortened to read as in Figure 1-3. In this figure, we have also eliminated the OPTIONS(MAIN) on the PROCEDURE statement, illustrating another form of language limitation— the limitation of a particular implementation. This clumsy attribute was only required in certain systems because of the interface with the oper- ating system, which required that MAIN programs be handled somewhat differently than subroutines. Of course, PL/I is noted for its absence of silly little restrictions such as abound in many other languages. To take just a few examples among

10 Programming as Human Performance XXX: PROCEDURE; DECLARE A(10000) FIXED(7,2), J FIXED BINARY; GET LISTC(CACJ) DO J’ = 1 TO 10000)); PUT LIST(‘SUM IS ‘, SUM(A)); END XXX; Figure 1-3 Using arithmetic generic sum. many, consider all the extra coding that has been written in FORTRAN because DO loops could not be counted backwards, because expressions could not appear as increments or bounds of an iteration, or because array subscripts had to start with one, or because only a small number of subscript expressions were possible. Still, we may not feel these limitations until they have been lifted from us, just as we often do not know we are sick until we suddenly feel better. Therefore, it is reasonable to expect that future languages will make us feel those limitations of PL/I that are not detectable today. Notice that this is a psychological question—one to which we shall have occasion to return. PROGRAMMER LIMITATIONS More directly psychological is the question of how much coding is done because the programmer did not have full mastery of his computer, his language, or himself. For instance, in our example, the programmer did not really understand array notation in PL/I—to the extent that he was unaware of the possibility of putting an array name in a data list in order to obtain all the elements of the array. Had he been familiar with this feature—which was, after all, even in FORTRAN—he might have written the program shown in Figure 1-4. XXX: PROCEDURE; DECLARE AC 10000) FIXED(7,2); GET LIST(A); PUT LISTC'SUM 1S *, SUM(A)); END XXX; Figure 1-4 Increased programmer awareness.

Reading Programs 11 There are, of course, programmer limitations other than merely not knowing the full power of the language—vocabulary limitations, we might say. For instance, the programmer may be unaware of certain algorithms, or he may be unable to grasp a sufficiently large portion of the problem at one time to see that certain duplications may be avoided. We shall have much to say about these and other limitations as we proceed, for these are obviously in the province of the psychology of programming. HISTORICAL TRACES We often find material in programs that might be accounted for under one of the above categories but is really present because of the history of the development of the program. For example, once the SUM function is Changed to an arithmetic generic function, there is no longer any reason for the program in Figure 1-2 to appear. Nevertheless, things being | what they are in the programming business, it is unlikely that anyone is going to delve into a working program and modify it just because the definition of the SUM function has been changed. And so, some years later, a novice programmer who is given the job of modifying this pro- gram will congratulate himself for knowing more about PL/I than the person who originally wrote this program. Since that person is probably his supervisor, an unhealthy attitude may develop—which, incidentally, is another psychological reality of programming life which we shall have to face eventually. The prehistoric origins of certain pieces of code are almost beyond belief. In one instance, two programmers digging into one of the basic codes at the Social Security Administration discovered a curious artifact. Whenever an input card with one of several origin codes was found to have an “A” in a certain column, the ‘‘A’”’ was transformed into a ‘1.” This was especially curious in view of the fact that only numeric values could appear in this column—and there was a preedit program to ensure that this was so. Still, the programmers were properly reluctant to modify some coding whose purpose they did not understand, so they started an inquiry. Eventually, they turned up a solution. Several years earlier—which means several programmer generations in some shops (which is another question of psychology, isn’t it!)—one of the keypunches at one of the contributing district offices had developed a bug which caused it to punch a “1” as an “A” in just this column. Since this was before the days of the preedit program, these mispunched cards managed to penetrate the inner program and caused it to hang up. By the time the problem was detected, there were an unknown number of such cards in circulation, so the simplest course seemed to be to make

12 Programming as Human Performance a “temporary” modification to the program. Once the patch was made, it worked so well that everyone forgot about it—more psychology—and there it sat until unearthed many years later by two archeologist pro- grammers. Not all historic code can be so easily differentiated as these examples might imply. In particular, the larger a program grows, the more diffuse are the effects of particular historical choices made early in its life. Even the very structure of the program may be determined by the size and composition of the programming group that originally wrote it—since the work had to be divided up among a certain number of people, each of whom had certain strengths and weaknesses. Indeed, the social organi- zation of programming groups will be an area of major interest to us. SPECIFICATIONS When we look at the difference between Figures 1-1 and 1-4, we might begin to believe that very little of the coding that is done in the world has much to do with the problems we are trying to solve. Everything considered, this would be a pretty fair statement of the situation—al- though there probably is, in almost every program, some code which actually does the work that was specified. Yet even if we succeed in extracting this kernel of the program, we must not be misled into the illusion that we could have started with this kernel as a specification and had some system take care of the other limitations. Aside from the obvi- ous difficulties in determining a programmer’s intentions when he doesn’t Know very much or in producing efficient code from a specification that is written without the slightest understanding of what computers can do, there will always remain the fact that, in most cases, we do not know what we want to do until we have taken a flying leap at programming it. Specifications evolve together with programs and programmers. Writing a program is a process of /earning—both for the programmer and the person who commissions the program. Moreover, this learning takes place in the context of a particular machine, a particular programming lan- guage, a particular programmer or programming team in a particular working environment, and a particular set of historical events that deter- mine not just the form of the code but also what the code does! In a way, the most important reason for studying the process by which Programs are written by people is not to make the programs more effi- cient, more compact, cheaper, or more easily understood. Instead, the most important gain is the prospect of getting from our programs what we really want—rather than just whatever we can manage to produce in our fumbling, bumbling way.

Reading Programs 13 SUMMARY There are many reasons why programs are built the way they are, al- though we may fail to recognize the multiplicity of reasons because we usually look at code from the outside rather than by reading it. When we do read code, we find that some of it gets written because of machine limitations, some because of language limitations, some because of pro- grammer limitations, some because of historical accidents, and some because of specifications—both essential and inessential. But for what- ever reason a particular piece of code gets inserted into the final product, there are psychological aspects to that reason—which leads us to believe that studying programming as human behavior will bear numerous and not always expected fruits. QUESTIONS For Managers

  1. If you are a first-line manager, are you capable of reading the programs written by your programmers? Or did your ability to read programs lapse with the previous generation of machines or languages? If you are capable, do you read them? If you don’t, why not try it and see what you find?
  2. If you are a higher-level manager, are your first-line managers capable of reading programs written by their programmers? Are you sure? Ask the programmers themselves, then answer this question again. Then find out if the first-line managers actually do read programs, even if they are capable. Our surveys indicate that nine-tenths do not, for one reason or another. Do you think it is possible for a first-line manager to know how good his programmers are or how well they are doing without occasionally reading their programs? For Programmers
  3. When was the last time you read somebody else’s program? Why has it been so long? When was the last time somebody else read one of your programs and discussed it with you? Was it your manager?
  4. Borrow a program from the program library or from one of your friends. Try to analyze it into pieces of code that are there for the various reasons described in the text. What did you learn from this exercise?
  5. Take one of your own programs written over a month ago, and analyze it as in Question 2. What did you learn from this exercise?

14 Programming as Human Performance BIBLIOGRAPHY Bucholz, Werner, ed., Planning a Computer System: Project Stretch, New York, McGraw-Hill, 1962. Computers too are made up of parts that get into them for various reasons. For an excellent view of how computing machines come to be the way they are, this book has not been surpassed. In addition, the book contains many insights into the question of machine limitations on programming, since Stretch was intended to be, among other things, a ‘“programmer’s machine” and thus eliminated many of the things which we take for granted on other machine designs. PL/I Language Log, IBM Corporation, Confidential File. This may be hard to obtain, but now that IBM is no longer solely responsible for maintaining the integrity of PL/I, it may be possible to see a copy. The Language Log is a running record of the controversies and decisions that went into the PL/I language we know today, and as such contains a marvelous education in how programming languages have been formulated. Hopefully, someone will pub- lish parts of this Log in a suitably organized book. Program Library of any user group or computer manufacturer. Your program library contains a wealth of information. Patronize it! Weinberg, G. M., PL/I Programming: A Manual of Style, New York, McGraw-Hill, 1970. Read this book if you want a lot more detail on the author’s ideas on how programs come to look the way they do. Gruenberger, Fred, ed., Fourth Generation Computers: User Requirements and Transition, Englewood Cliffs, N.J., Prentice-Hall, 1970. Looking to the “fourth generation” with all the wisdom garnered from the first three, several authors in this collection seem at last to be facing the problem of the psychological needs of the computer user. Murray Laver traces the ways in which designers, salesmen, and manufacturers have had more influence in the past than the people who were to use their products. Jacques Bouvard discusses the need for more user orientation in the design of systems at the software level.

Silver Anniversary Notes Comments on Chapter 1: Reading Programs Not much has changed here. The reading of programs is still the key to understanding how we make programs. One improvement is emerging: libraries of works to study—such as class libraries—though these generally lack the criti- cal commentary that would make them a more valuable training resource. However, the patterns movement is addressing this need, but much work must be done: One of the obstacles organizations claim keeps them from moving to a new technology is the effort required to understand the class libraries that come with the development environments. One change is the growth of historical traces in code. After all, they’ve had twenty-five more years to accumulate, and they have definitely accumulated. This accumulation is bad for software maintenance, but possibly good for the study of programming as human behavior, assuming we have access to these traces and some documentation suggesting how the code got that way. However, the code that’s read most frequently during software maintenance is usually not the best of examples. Mostly, that’s why it is in maintenance in the first place. Reading code won't help much if the reader has no sense of what’s good and what’s bad. That much hasn’t changed in twenty-five years. ‘But why is it so hard for developers to submit their work for review by others or to try to improve their own skills by reviewing the work of others? Curiously, superior developers tend to find value with walkthrough and inspection process- es while the merely clever do not. So, as always, the good get better and the bad get worse.

r
Wl
eh
et
ae
wae
ws -)
ee
a
poner: ie ial
|
De ee
oe
7
ay
mh: ee t4
anes st adie the ge
a i
rR tay cueing:
ah
4
sfyet
Gueerd tel.
°4 eceiie) ne
_ Apsalh
_e
hgh
Alii
ort toe Sh hag
My ‘ * iy Bical a
ft t s €
(ook
“ain
ieee
extn
|
rae, Pade tephra
Pepe 0 seta Att B
al

4 Pye Hh, ae oe, am ee ee ne bs ’ f year othe p 1 i ; VeRO Dy | £ Mure! on Ty aw Fore, eoreit 9 to) vy detuit cor relates iw on New i yod om ie see ig 1G OF ibysey ety “pen b Rise i ety, oni t Jaen “Ay pia ie an SPOR Se ie off Bae She oie a, leah a ioe esto ag a a SALGtee QUE se se went. g Cort edment ow See . Vit Ow Bier ne Deoryiay erieer ROS, Hiei avert? “n Tt VSR ’ “a, Deg as % ahi.

bi g ie ay Af nt eat pa wy 2 Magma eee L ayy aL BY . ah ‘| eee reba Larakoranggn, ot apne ges, 08, Bh ue seiapi ye

  • ainamnonivn prapeini anttn bart av’ yee) ty wae Shay A omy lenbotait ws (Avg en a 6 ; x heleh« wags Yaitey oven ver! ble oleliumucs of 2168Y momo hing y ati sot boop yicieegn RIG .eoonfatian eswites 10) bed al | mOOe @ azar ol ezaocs eyed ew gninuees. roared nemud ey Qaimme pow vee te oi og ico ari wor! piiissggue NolEmaMWaab amoe bf a anaane) eit onenieg grinds yiaupar Jac bath eat aboo art aBve KR Oe 7 Con eteKRNT Am nS yeti Saat oe a ea bite bone eetw er oamR 8 aM bm er 1 autn le FIBH Boo 28 = Sateen ii. si ‘ert We TON oF Ha Men 2k ye Nlewrol wx ape age cds os och | 7” f even OY = ¥. ae id iB ch ie J

Powered by TurnKey Linux.