When we follow the way of the engineer, we use an analogy between the design of reliable material objects and the design of reliable immaterial software. Engineers follow a standard process for creating physical objects. We note the methods that can prevent or identify defects that are introduced during phases of the software-development process. Engineers design useful objects by following standards, and we suggest ways to prevent software defects by following standards.
James Adams provides in his book Flying Buttresses, Entropy, and O-Ring: The World of an Engineer [Ad91] a diagram that shows the engineering process having the following stages (p. 39):
The three stages that are of most interest to us are preliminary design, detail design, and development. Adams defines these stages as follows ([Ad91], pp. 44–45):
Preliminary design: Various ways of solving the problem are conjured up and compared. Toward the end of the process, a decision is made as to which design to pursue, and the overall configuration of the product is defined.
Detail design: The product is completely defined in its final form. This means that each component of the product is described so that it can be produced and so that the whole will fit together into a balanced and integrated product.
Development: Prototype products are brought to a functional and economic level that will satisfy customers, whoever they may be, and the producers.
These three stages correspond to the software-development phases of design, coding, and testing. There are significant differences, however, between the development of software and the engineering of tangible objects.
One of the most important results of the preliminary design of an object is a mathematical analysis of whether it will operate safely and serve the purpose for which it was designed. This isn’t always done. Sometimes the scientific theory doesn’t exist to resolve these issues. In other situations, the computation required to apply the theory to the product in question is beyond current computers.
In Invention by Design: How Engineers Get from Thought to Thing, Henry Petroski [Pe96] states, “The ability to calculate is the ability to predict the performance of a design before it is built and tested…. Calculations that indicate failure conditions in the design enable the engineer to modify and remodify the design until it is ready to be realized.”
The designer of a software system has no opportunity to apply the laws of physics to validate his design mathematically. One can validate the design of disks and memory that will store software and circuits that will execute it. The software itself, however, has no tangible referent to which the laws of physics apply. This makes software infinitely malleable. Unfortunately, it also places the software designer at a severe disadvantage vis- -vis his or her engineering counterpart when it comes to validating a design.
In To Engineer is Human: The Role of Failure in Successful Design, Henry Petroski [Pe92] states the following:
Engineers … make mistakes in their assumptions, in their calculations, in their conclusions. That they make mistakes is forgivable; that they catch them is imperative. Thus, it is the essence of modern engineering not only to be able to check one’s own work, but also to have one’s work checked and to be able to check the work of others.
Software designs are typically validated by peer review. The same is true of designs for tangible objects. The opinions of experts are often useful in identifying flaws in a design, but they’re no substitute for mathematics.
Discussion of the peer review methodology is beyond the scope of this work. See the bibliography for recommended books on this topic.
The output of the detailed design phase of a tangible object is pictorial representations and textual descriptions of the object and the process for manufacturing or building it. The output of the coding phase of software development is a textual description of the software and instructions necessary for building a representation of that description in a form that can be executed by hardware.
Another aspect of the relationship between the detailed design phase of a tangible object and the coding phase of software development is the use of standards. For tangible objects, a variety of standards must be followed. Some standards come from manufacturer’s groups that wish their products to be able to work together. Other standards come from government regulatory bodies or insurance underwriting organizations. Professional societies also recommend various standards for engineers who work in a particular field. There are also internal standards that a given organization imposes upon itself. These standards all serve to channel detail-design decisions in certain directions, resulting in products that are safer, more reliable, and more useful.
There are no universal required standards for software. Nonetheless, wise software developers use standard methods for coding to improve reliability and maintainability.
Thus, the first major aspect of the engineering worldview that is valuable in the debugging enterprise is the attitude of defect prevention. The engineer designing a tangible object uses analytical, experimental, and methodological means to identify and remove potential sources of failure. The remainder of this chapter is devoted to explaining methods for preventing defects that are applicable during the coding phase of software development.
Defect prevention is also important during the design phase of software development. Using object-oriented analysis and design methodology is a good way to prevent defects during the design phase. Discussion of this methodology is beyond the scope of this work. See the bibliography for recommended books on this topic.
Of course, thorough testing is critical to defect prevention in software. Discussion of testing methodology is beyond the scope of this work. See the bibliography for recommended books on this topic.
The second major aspect of the engineering worldview that is valuable in the debugging enterprise is the attitude of leveraging failure to achieve future success. Henry Petroski does an excellent job of advocating this mindset in several of his books. In Invention by Design: How Engineers Get from Thought to Thing, he states, “It is the analysis of failures or of limitations of a design that leads to improved understanding and thus to improved products.”
The entirety of Chapter 11 is devoted to explaining methods for analyzing the root causes of software defects. The purpose of this analysis is to ensure that one identified defect can be leveraged into many defects prevented.
The third major aspect of the engineering worldview that is valuable in the debugging enterprise is expecting unexpected failures. Engineers who build physical objects provide a safety factor in their designs. They acknowledge that there are limits to the strength of their designs and that unknown factors might make the design weaker than their analysis shows.
While software developers can’t specify extra structural or material integrity, they can include debugging infrastructures in their programs as they develop them. By acknowledging that there will be flaws in their design that they haven’t anticipated, they can prepare to make it easier to debug when those flaws are revealed.