Broken Programs

I’m a programmer by profession, so I sometimes wonder: why are most programs so bad? All sizeable programs are full of bugs. Mostly these bugs don’t matter so much, but why are they there? If computer hardware had as many glitches as computer software, computers would never manage to boot up at all.

My current suspicion is that one of the root problems is underspecified interfaces. All programs are stitched together out of a number of different modules. Those modules all communicate via interfaces. The interfaces are generally documented reasonably well, but they are underspecified. Rarely does the interface say “you must be able to allocate 10M of memory” or “your network must be working” or “you must not open a dialog box now” or “the user must have logged in.”

To put it another way, every module of a program makes a set of assumptions about the environment in which it will work. Those assumptions are normally implicit. Violating those assumptions will cause unexpected behaviour. That behaviour will sometimes be a bug.

Other engineering disciplines spell out their assumptions in detail, apart from physical assumptions like “object will be constructed on planet earth.” For example, structural engineering drawings for a house specify exactly what bolts and nails should be put where, and the calculations show exactly how the load will be borne. A safety factor is included, to protect against unexpected weakness in the materials, or shoddy work by the builders.

Why are there so many implicit interfaces in computer programming? Because programs are very complex. We simple don’t know how to design and implement very complex systems.

How can we make this better? I don’t think the answer is to implement better interface specifications. I think it is more likely to be to make programs much much simpler. The growing use of tiny applications is a positive step–except, of course, that they must run in a very complex environment. One of the significant advantages of Unix when it was developed in the early 70s was that it implemented sets of small programs, and provided a very simple way for them to communicate: the pipe. Unfortunately, while the pipe is very simple and convenient, it is not enough to construct a modern application.

I think that when working on a complex program, ones primary goal has to be to continually simplify. Individual modules should not make any assumptions. Communication between modules should be explicit. Modules should be idempotent whenever possible, and when they must store data it should be explicitly stated in the interface. Development tools should enforce these conventions.

I know that none of this is original or new. And we have learned things over the years: todays systems are much more complex than the systems of thirty years ago. But they still have just as many bugs, and it seems like the bugs are harder to fix. We have a long way to go.

(I’ll be travelling for the next couple of days, and may not post.)


Posted

in

by

Tags:

Comments

Leave a Reply