Many students of the art hold out more hope for object-oriented programming than for any of the other technical fads of the day. I am among them. We must be careful to distinguish two separate ideas that go under that name: abstract data types and hierarchical types, also called classes. The concept of abstract data type is that an object’s type should be defined by a name, a set of proper values, and a set of proper operations, rather than its storage structure, which should be hidden.

Hierarchical types allow the definition of general interfaces that can be further refined by providing subordinate types. The two concepts are orthogonal - there may be hierarchies without hiding and hiding without hierarchies. Both concepts represent real advances in the art of building software.

Each removes one more accidental difficulty from the process, allowing the designer to express the essence of his design without having to express large amounts of syntactic material that add no new information content. For both abstract data types and hierarchical types, the results is to remove a higher-order sort of accidental difficulty and allow a higher-order expression of design.


Many of the classical problems of developing software products derive from this essential complexity and its nonlinear increases with size. From the complexity comes the difficulty of communication among team members, which leads to product flaws, cost overruns, schedule delays. From the complexity comes the difficulty of enumerating, much less understanding, all the possible states of the program, and from that comes the unreliability. From the complexity of the functions comes the difficulty of invoking those functions, which makes program hard to use. From complexity of new structure comes the difficulty of extending programs to new functions without creating side effects. From complexity of structure comes the unvisualized states that constitute security trapdoors.


Following Aristotle, I divide them into essence-the difficulties inherent in the nature of the software - and accidents - those difficulties that today attend its production but are not inherent.

The essence of a software entity is a construct of interlocking concepts: data sets, relationships among data items, algorithms, and invocations of functions. This essence is abstract, in that the conceptual construct is the same under different representations. It is nonetheless highly precise and richly detailed.

I believe the hard part of building software to be the specification, design, and testing of this conceptual construct, not the labor of representing it and testing the fidelity of the representation. We still make syntax errors, to be sure; but they are fuzz compared to the conceptual errors in most systems.

If this is true, building software will always be hard. There is inherently no silver bullet.

Inherent properties of this irreducible essence of modern software systems: complexity, conformity, changeability, and invisibility.


Different levels of documentation are required for the casual user of a program, for the user who must depend upon a program, and for the user who must adapt a program for changes in circumstance or purpose.

To use a program. Every user needs a prose description of the program. Most documentation fails in giving too little overview. The trees are described, the bark and leaves are commented, but there is no map of the forest. To write a useful prose description, stand way back and come in slowly:

  1. Purpose. What is the main function, the reason for the program?
  2. Environment. On what machines, hardware configurations, and operating system configurations will it run?
  3. Domain and range. What domain of input is valid? What range of output can legitimately appear?
  4. Functions realized and algorithms used. Precisely what does it do?
  5. Input-output formats, precise and complete.
  6. Operating instructions, including normal and abnormal ending behavior, as seen at the console and on the outputs.
  7. Options. What choices does the user have about functions? Exactly how are those choices specified?
  8. Running time. How long does it take to do a problem of specified size on a specified configuration?
  9. Accuracy and checking. How precise are the answers expected to be? What means of checking accuracy are incorporated?

Often all this information can be set forth in three or four pages. That requires close attention to conciseness and precision. Most of this document needs to be drafted before the program is written, for it embodies basic planning decisions.


A baseball manager recognizes a nonphysical talent, hustle, as an essential gift of great players and great teams. It is the characteristic of running faster than necessary, moving sooner than necessary, trying harder than necessary. It is essential for great programming teams, too. Hustle provides the cushion, the reserve capacity, that enables a team to cope with routine mishaps, to anticipate and forfend minor calamities. The calculated response, the measured effort, are the wet blankets that dampen hustle. As we have see, one must get excited about one-day slip. Such are the element of catastrophe.


For picking the milestones there is only one relevant rule. Milestones must be concrete, specific, measurable events, defined with knife-edge sharpness. Coding, for a counterexample, is “90 percent finished” for half of the total coding time. Debugging is “99 percent complete” most of the time. “Planning complete” is an event one can proclaim almost at will.

Concrete milestones, on the other hand, are 100-percent events. “Specifications signed by architects and implementers,” “source coding 100 percent complete, keypunched, entered into disk library,” “debugged version passes all test cases.” These concrete milestones demark the vague phases of planning, coding, debugging.

It is more important that milestones be sharp-edged and un-ambiguous than that they be easily verifiable by the boss. Rarely will a man lie about milestone progress, if the milestone is so sharp that he can’t deceive himself.


When one hears of disastrous schedule slippage in a project, he imagines that a series of major calamities must have befallen it. Usually, however, the disaster is due to termites, not tornadoes; and the schedule has slipped imperceptibly but inexorably. In deed, major calamities are easier to handle; one responds with major force, radical reorganization, the invention of new approaches. The whole team rises to the occasion.

But the day-to-day slippage is harder to recognize, harder to prevent, harder to make up. Yesterday a key man was sick, and a meeting couldn’t be held. Today the machines are all down, because lightning struck the building’s power transformer. Tomorrow the disk routines won’t start testing, because the first disk is a week late from the factory. Snow, jury duty, family problems, emergency meetings with customers, executive audits - the list goes on and on. Each on only postpones some activity by a half-day or a day. And the schedule slips, one day at a time.


Bug-proofing the definition. The most pernicious and subtle bugs are system bugs arising from mismatched assumptions made by the authors of various components. In short, conceptual integrity of the product not only makes it easier to use, it also makes it easier to build and less subject to bugs.

So does the detailed, painstaking architectural effort implied by that approach. The crucial task is to get the product defined. Many, many failures concern exactly those aspects that were never quite specified. Careful function definition, careful specification, and the disciplined exorcism of frills of function and flights of technique all reduce the number of system bugs that have to be found.

Testing the specification. Long before any code exists, the specification must be handed to an outside testing group to be scrutinized for completeness and clarity. The developers themselves cannot do this. They won’t tell you they don’t understand it; they will happily invent their way through the gaps and obscurities.


An ancient adage warns, “Never go to sea with two chronometer; take one or three.”