Classic Computer Magazine Archive START VOL. 1 NO. 1 / SUMMER 1986

PERSPECTIVES

Voodoo

Computing

The Pragmatic Art of Defensive Programming

BY DAVID SMALL

Being a rational contemplation of the vagaries surrounding computers, programming, and the precariousness of heavenly bodies and telephones in juxtaposition to floppy disks. Mr. Small expounds upon mayonnaise, cosmic rays and his personal, violent hatred of structured programming.

To the outsider, computers are clean, utterly rational and cut-and-dried. They appear to be the same machines I was taught about at college: number crunchers governed by strict physical laws.

When I graduated and entered the real world, I learned it just ain't so. And over the past ten years. since my initiation into Hackerdom, I have formulated a valuable principle, which I will share with you.

But first, let us examine for a moment a typical computer, to get an idea how uncertain and fragile a medium it is.

DIGITAL AMNESIA

We'll begin with memory a frighteningly transient thing. Most personal computers today use "dynamic. RAMs." a Faustian bargain to pack a lot of memory into a small area. The dynamic means that if you don't access that memory at least 100 times a second, it will fade away.

Now, you say, you've got to be kidding. One hundred times a second? That's pretty fast. But every computer working today is actively struggling just to keep its marbles. Turn on an Atari 8-bit computer; just sitting there, displaying "Ready," it is continually accessing and "refreshing" its memory

Now let's talk about cosmic rays. Cosmic rays have a truly witty effect on dynamic RAMs. They make memory cells flip randomly

Used to be, with the older RAMs, memory wasn't so sensitive. Not anymore. In Denver, a personal computer owner can reasonably expect one memory "soft hit," or failure, per week, during normal solar activity; this gets worse during solar flares.

Dynamic RAM chips are also the most skittish and easily zapped chips known. They have a nasty habit of "ringing" and "undershooting," which means they generate negative voltages which they feed to other chips, destroying all the chips involved. Also, any brief, transient power "spike," (like your next door neighbor's washing machine turning on), can flip a few bits.

Count on this: For every system crash caused by RAM failure, there are ten unseen events where RAM bits get flipped.. They just happen to get flipped somewhere where it doesn't matter at the moment.

Think of dynamic RAM as 65,536 dominoes stacked on top of each other. One small push, and down they go.

And then, there are diskettes.

TRUST NOTHING

Data is stored on diskettes with tiny tiny tiny magnetic fields, which are both remarkably durable and very sensitive. For instance, my daughter Jennifer once smeared mayonnaise across a 3 1/2-inch diskette (opening the little sliding door to do it, too). The diskette survived. However, I once had a phone ring next to a diskette; the diskette was completely erased. (Now I treat the phone as if it had the plague and keep it across the room.)

And how about keyboards? When you press a key you bring two contacts together. What you're not told is that those contacts bounce against each other before coming to a rest, something like dropping a bouncy rubber ball. Whenever the computer looks for a key, it must deliberately wait for awhile before looking for another key, because the first key is still rattling from being pressed.

I could go on about rise times, about marginal clocks, about how even trying to view a crystal with an oscilloscope will cause the crystal to quit working. But the end point remains the same: Computers are a very "iffy" item.

You are working in a medium that is lucky just to keep running, that often fails through no fault of your own. Add to this the fact that human beings are not perfect and computers demand perfection in their programming, and you get the ultimate question of the Frustrated Programmer: Is this problem in my program or in the computer?

Something wonderful, childlike, and naive dies in a programmer the first time a computer genuinely screws up. Up to that point, you are sure the problem is yours, somehow, somewhere. Afterwards, you are never the same. It's like learning the truth about Santa.

So what philosophy does a sane person adopt?

Working with computers is like performing sorcery. Treat programming as you would treat casting spells. You'll go far.

Just as sorcerers drew pentagrams to control and bind the demons they summoned, I find I must adopt certain defensive measures to prevent computers from causing a lot of trouble. My philosophy is contained in ten maxims.

MAXIM NUMBER ONE:

When you're having a bad day, stop working.

Every programmer has had days like this. Compilers mysteriously quit working. Disks stop loading. The hard disk flakes out. Nothing works right. You sit and think of alternate approaches, try them, and find your way blocked. The next day, of course, everything works right.

The thing to do here is to quit. Consider yourself bad luck that day. Anything you touch is going to fail. Remember those cosmic rays massaging your memory chips.

So lock your backup disks in a vault, and go do something useless, like creating a structured design for your next program.

MAXIM NUMBER TWO:

Comment your code to death.

Dark Ages spellcasters wrote down every detail of their spellcasting in their spellbooks, or "grimoires," because they wanted to be able to retrace their steps in case of failure. Accept that your memory is not perfect. You will probably have to return to your code one day and fix it, or use it in another program. So comment it. It only takes a minute more, and it pays for itself many times over.

MAXIM NUMBER THREE:

"Programming is an art best learned by apprenticing to a master. Or "Steal from the best." (Quote attributed to Russell Smith.)

Medieval sorcerers had no problem with borrowing each other's spells. Working out a spell, and keeping the demons from snatching you away to the inferno, was no easy task, right up there with debugging assembly language. Once you got something working right, it was most valuable.

Good programmers, the true Hacker brethren, know this instinctively. This is why they are usually happy to share code. And looking at someone else's code is often the only way to pick up clever tricks.

Chris Crawford taught me all about ensuring that the decimal flag is cleared before doing interrupt processing; otherwise, arithmetic you do on the 6502 during interrupts can mysteriously go bad, unpredictably and untraceably

John Harris found sections of his sound generation code (from Frogger") being used in other games. Rather than being insulted, he understood the implied compliment: His code was worth copying.

So, let other people look at your code. Don't be embarrassed; asking for comments is the sincerest way to flatter someone.

Find out who your local hackers are and join their group. Hackers are basically people who believe in freedom of information exchange. If you become part of the loose, informal hacker group around you, you will have access to code, tools, and amazingly creative people.

MAXIM NUMBER FOUR:

Use the best tools, and be willing to pay for them as necessary. Your time is valuable, and it is a pleasure to use good tools.

Use quality assemblers, compilers, interpreters. The time spent tracking down just one bug in your tools is worth the cost of using good tools to begin with. After all, you wouldn't expect sorcerers to skimp on the quality of newt eyeballs if they thought their spells might backfire.

Use fast tools. You'll be assembling, compiling and interpreting many times on any project. Even saving a few seconds per assembly is worth it. This also makes hard disks and RAMdisks worthwhile. The time you save is your own; nothing is more stultifying to the senses than watching a computer do something for the eightieth time.

Fast tools include a fast printer. You need to make lots of printouts as part of the game. If you stick with something that prints slowly, you'll be waiting a long time before you can make progress.

On my most recent project, making an Atari ST think it was a Macintosh, the program ended up being 7000 lines long (which ought to tell you something about how loosely my head is screwed on; it's all assembly language, too). Anyway the printout is 120 pages long and takes awhile to print. Not a good job for a slow printer.

The time you save pays for itself. Your work gets done faster, which in the case of a freelancer, means you are available for other work.

MAXIM NUMBER FIVE:

Keep a copy of everything you do-disks and printouts. Put it somewhere, file it away but keep it. You will always come back to it.

Corollary: Reformat a disk you will "never use again" and you'll need it tomorrow

Among the very few bright things I did at college was to keep most of the programs I wrote, just one extra printout. It only took a minute back then. And now I have a library of debugged routines and software.

This is especially important to freelancers. You haven't time to redevelop the wheel, and it is impossible to remember everything about a project you did awhile back. But if you have a printout of, for instance, how to set up a player-missile table, and better yet, if you can import that code off an old diskette directly into the editor, you've saved a lot of time.

Remember the John Harris syndrome: He kept all his floppy diskettes, including the master to the superb "Frogger," in one notebook. Once, he went to a computer show and demonstrated that disk. Someone stole the notebook and he lost all his disks and an incredible amount of development time. This is the real story of why a pirated Frogger showed up a year before the real Frogger; John was busy rewriting all his old code.

MAXIM NUMBER SIX:

Backup your backups. Keep three of everything.

Computers typically fail as you back up the master of your program. This takes out not only the master, but the backup, since both are in the computer at the same time.

The solution is a third diskette. Just write a copy of your current program out to it every so often, then take it out and file it.

Don't be hasty to use your backups. Whatever killed your master disk might take the backup, too. Make sure you've fixed the problem. Test first.

Recently, I had the charming experience of trashing an Atari ST hard disk. I closed the current directory and opened up the backup disk to repair the hard disk. The backup's directory promptly and permanently disappeared, leaving me the fun job of retyping the whole program I had been working on.

MAXIM NUMBER SEVEN:

Frame this; hang it over your desk: Don't be clever.

There are so many clever tricks to use in a computer, and so little reason to use them. Unless you really need the speed and code size of a clever hack, avoid it. There are always side effects.

Some sorcerers used Latin and took other steps to make their spells unintelligible. They used lots of incense (which reminds me of structured programming: It makes your eyes hurt, and confuses the whole ceremony but does make you feel you have accomplished something).

Avoid Utterly Clever Constructs. The worst offender in this department is C, which I have to come to see as an abbreviation for "Clever." C is a wonderful language to write code to show off with; "Gee, Fred, I never thought of doing it that way."

Fortunately, it is possible to write legible C code, that actually can be understood when reread. (This is contrasted to APL, a language once accurately described as "Write Only".)

Anyway odds are, in a month, you'll forget just how that witty piece of code works, so why go to all the bother?

MAXIM NUMBER EIGHT:

If it works, don't fix it.

The computer doesn't care how it looks. So it's a kludge? An utter pile of trash? So what? If it works, leave it alone and do something else.

Skip the indenting of your code; don't sweat the trailing comments and "pretty printing." Don't be a neat-freak; neat-freaks accomplish little. Leave it and go do something else. You owe it to yourself.

Consider code development as you would consider crossing an unstable, dangerous bridge. Sure, maybe you have to do it once. But who wants to do it twice? Look at Chris Crawford's Eastern Front code. There are sections that are not clean, elegant, or structured. It works. It is art. Who cares what the code looks like?

MAXIM NUMBER NINE:

Always give your code the maximum chance to work. Or: It'll always think of something you don't.

When summoning demons in the old days, you wrote detailed contracts specifying exact terms of employment and payment. You tried to think of every condition-because demons were notorious for wriggling through loopholes. Really smart sorcerers added a "catch all" to the contract to cover what they didn't think of.

Do the same. Write defensive code.

Using a variable? Initialize it just before you use it. Don't depend on its value staying the same from the start of the program; you might use it for something else, or, (horrors!) the memory location it occupies might get clobbered accidentally.

Don't end a loop just by checking for a value equalling another value. Check for greater than or equal, or less than or equal; you might miss the equaled value. Give your program a chance to recover gracefully

MAXIM NUMBER TEN:

Structured programming is useless in the real world. You don't need to program in a structured way. Give yourself some credit. You're neither a moron nor a menace to society. Don't use a language that forces structure on you.

Corollary: If a GOTO statement is so terrible, how come every microprocessor has one? And uses it frequently?

Pascal, to quote Chris Crawford, is the fascism of computer languages. And Pascal is The Great Language of Structured Programming. You can only do things one way-and there's a lot of mindless quibbling you have to go through to get it done.

Pascal also produces notably inefficient code, for the simple reason that computers don't use structured code, people do. Putting it mildly, something is lost in the translation. Personal computers are not yet at the point where you can afford to throw away a great deal of processor time letting the computer trundle through your "structure."

It is fine to draw up a general idea of what you're going to do, but carry it too far, and it's like working inside a straitjacket. You cannot think of everything at once, and that includes the structure of your program. Try to lay everything out in the beginning and you will throw out all the perfectly good ideas which occur during the coding process.

So use an anarchist's language such as C and obey just enough rules to get by. Don't take any extreme position, be it writing a thousand lines of uncommented assembler or prestructuring your program. Remember, there are enough things working against you that you must retain maximum flexibility to get things done.

CONCLUSION

Thus ends my Pragmatic Programmer's Philosophy. But I have more ideas. Many more. Should I be given the opportunity to speak again, I could tell you about Avoiding Burnout: The Career Programmer's Plight, or Fooling the Boss with Massive Printout. If the START editors will only let me.

(Editor's note: Perspectives is a forum for commentary on the programmer's art by its diverse practitioners. START welcomes reader response to the ideas and opinions expressed in this department.)