We are used to textual material having a “final form.” J. D. Salinger’s Catcher in the Rye and Tom DeMarco’s Controlling Software Projects (both excellent books, but for different reasons) are “done.” They are not going to change — at least until a new edition is published. Programs, however, are never “done.” Programs are always subject to maintenance: modification to do something different, modification to do the same thing in a different context, correction of discovered defects, and so forth.
Programs, therefore, have two distinct audiences. Every program is a process description, for which the audience is a computer. Every program is also a record of the programmer’s thought processes, for which the audience is a maintenance programmer. The maintenance programmer may well be the original author.
Since there are two audiences for the work that is the program, a valuable question to ask is “which audience is more important?” Clearly, the program should do what it is supposed to do. But we also find the lifetime cost of maintenance frequently exceeds the cost of original development. Every investment in making a program easier to understand is paid back, frequently many times over, in the maintenance phase of the program’s lifetime.
This did not used to be the case. Even twenty years ago, the best investment of effort was in making programs faster and smaller. However, computer power doubles roughly every 18 months — an observation called Moore’s Law. Computer power is now so cheap that the best investment lies in minimizing labor, not computer power. Some problems are at the ragged edge of computational feasibility, and making programs faster and smaller makes sense for those problems. The vast majority of problems, however, do not stress available computational resources. For this majority of problems, making the program easy to understand is more important than making it get all the available computational power out of the computer.
It is not worth three seconds of a $25/hour apprentice electrician’s time to pick up a penny lying on the ground — that three seconds, if chargeable at $25/hour, is worth over two cents. Similarly, computer power is so cheap, and computer programmers so expensive, that almost any attempt to save computer power costs more in labor than it saves in computer costs. There are, of course, exceptions to this rule of thumb. For example, if the program is going to be used a great many times — as when the program will be a product for sale, or will be widely distributed and heavily used within the developing organization — it is frequently worthwhile to expend effort in minimizing the computer resources required. Alternately, if the economics of the situation are skewed by cheap labor (as with hobbyists or prison inmates), marginal computer systems, or excessive computer costs (as with IT departments that charge for memory usage), a different trade-off may be indicated. Generally, however, programming for efficiency is counterproductive.
The most important attribute of programs is reliability — the program should give the right answer, always, or at least fail to give a wrong answer. The next most important attribute of programs, however, is maintainability — programs should be easy to understand and to modify. This has implications for the ways in which both initial development and maintenance are performed.
In initial development, the thrust should be on simplicity: simplicity of algorithm and simplicity of implementation. The implementation should straightforwardly implement the algorithm chosen. Let us revisit our friend, the factorial function. The calculator code sequence:
X→A:1→B Lbl 0:AB→B:Dsz A:Goto 0 B
is, for positive integer values of X, equivalent to the calculator code sequence:
1→B For 1→A To X AB→B Next B
The latter code sequence, however, is much easier to understand, and is therefore to be preferred. The latter sequence also works for an X value of zero, and so is slightly more functional than the first sequence.
The general effect of maintenance is to increase the complexity of the program. The attractive approach to a maintenance need is to make the minimal change to the program that will have the effect desired. However, these minimal changes frequently change the overall structure of the program, and have a “dirtying” effect on the design or implementation. For example, it may be that the factorial function was needed in only one place, and so was coded as a loop in that place rather than as a subroutine. When the factorial becomes needed in another place as well, the minimal change is to code it, too, as a loop in that other place, rather than as a subroutine. The best change, however, is to code a factorial subroutine, and call it in both places where the factorial is needed.
In maintenance particularly, we must borrow a concept from extreme programming: “refactor mercilessly to keep the design simple as you go and to avoid needless clutter and complexity.” Refactoring means making appropriate changes to the program design so its design cleanly reflects its modified function. This refactoring step frequently increases the immediate expense of a change — but this investment pays off in increased simplicity of future changes.
Modification to the plot of a novel is successful only if the implications of the plot change are propagated throughout the novel. The pun on a character’s name in chapter 3 makes no sense if the character is called something else in all the other chapters. The butler being the murderer makes no sense if the dénouement is the only place where the butler appears. Programs are similar to novels in that they have a structural integrity. In this way, programming is an exercise in literature: literature whose audience is the maintenance programmer.
Copyright © 2001 Brian Hetrick
Page last updated 30 December 2001.
Data Structures I
Building Blocks II
Data Structures II