I wrote this book in what now looks like the dawn of antiquity. I was on the Windows 95 development team at the time – C++ was still new, we still wrote the time critical parts in assembler, and Java was a word for coffee. It was a challenging world back then. Not better than today, not worse – but different challenges.
I went back and looked at what I wrote. A lot of it is specific to C, C++, and assembler. Some of it is specific to the state of the industry at that time. And those parts will only be of interest to a few with a large degree of curiosity about that time. A bit more will be of interest to people still writing C++ in an unmanaged environment.
But the first two chapters, those are still every bit as relevant today as they were when the book was written. I think most developers can be well served by reading this as it takes a philosophical look at how to write code with fewer bugs.
You can download the entire book for free at No Bugs! You may forward the free copy to friends, post it on your own website, etc. Below is a short excerpt from chapters 1 & 2 if you want a peek before downloading.
One interesting note, in chapter 2 it declares bugs should be called Massive Fuck Ups. The use of the F word had to be approved by a Vice President at the publisher and I think to this day No Bugs! Remains the one programming book from a major publisher where the word appears.
The following is © Copyright 1992 by David Thielen - All Rights Reserved
We've all been there. We've finished up our new application. It's been copied and shipped out the door. It's arriving at our first customers - and the phone rings.
It starts as a technical support question. But the problem gets escalated and pretty soon it becomes obvious - there is a bug in the program.
And not just some little insignificant bug that user's can work around - this is a big hairy bug that gets right in the face of each and every user and essentially stops them from using the program.
It doesn't matter how many customers you have, having to replace 100% of the copies of your program out there is a horrendous expense. And the cost is not limited to actually replacing the disks. You now have a reputation for delivering buggy software. This reputation will be costing you sales for the next several years - perhaps enough that a product that would have succeeded now fails.
If you cringe every time the phone rings after shipping a new product - then this book is for you.
These bugs can have more than just a financial impact. The most standard program in the world may be in use in a cardiac care unit in a hospital. A small failure in a copy program could change a number in a loan application. A vertical market application may have a businessman reporting incorrect information to the government (which happens to be a felony). Somebody's word processor was used to type up the specifications to the airplane you are flying in.
People come to depend on programs in ways that the author never foresaw or intended. But they do depend on these programs. And just as you expect the airplane you are flying in to not come apart in mid-air, people expect their programs to operate as expected.
Users now expect, and in many cases get, software which, while not bug free, they will never see a bug in. Over the next several years, they will demand this robustness in all of their programs.
I recently had this bug in some code reading from a data port. What was driving me crazy was that while I was reading the data a byte at a time, every once in a while my buffer pointer would be off by two.
I placed assertion checks throughout my code to make consistency checks. And the same thing kept happening - it would pass the tests until suddenly it was off by two.
Finally I asked a co-worker to take a look at the code. After studying it for awhile, he came back and said he saw nothing wrong assuming the function calling me hadn't set the direction flag (we're into x86 assembler here).
To make a long story short, the function calling me did not guarantee to clear the direction flag. It's just that it was usually clear.
Not only could this bug have slipped through - I wasn't even testing properly for it. In an environment we make assumptions (such as n = 1 + 2; will give us 3). Unfortunately, we almost always include in this list of assumptions things that are almost always true.
To add insult to injury, a summer hire porting this same code came in and pointed out that I didn't clear the direction flag. I showed him where I did it earlier but told him about spending a day determining that I had to do it. He told me that I just should have shown it to him first - which is unequivocal proof that summer hires should be tortured.
Another case many years ago I wrote a program that included a weird kind of word processor. Because of the requirements, the file format of the word processor was quite complex and we had some bugs in the code.
This was in the early days of the PC and I didn't have all the ideas laid out in this book to use writing the program. There were some bugs in how we were handling the file format. I knew that much but I couldn't seem to find that bugs - at least not all.
Finally, in desperation, I put code in to check the consistency of the file and to correct it when it found problems. As time went on, I found additional bugs in my regular code, which I fixed and I added to the consistency checks and error correction.
While I kept reducing the bug occurrences, I couldn't eliminate them. Finally, to make testing easier, I ripped out the consistency checks and error correction to track down the bugs - and the bugs went away. I had apparently fixed the original bugs but bugs in my bug-fix code had introduced new bugs in the meantime.
And then there are the horror stories you hear of elsewhere (thank god there is always someone doing something much dumber or worse than you).
There is one company where they preferred to not test the product because then bugs were reported and they would have to fix them. Of course, when the users reported the bugs they had to be fixed anyway.
At another company, management would schedule when all bugs were going to be fixed and on that day, by definition there were no remaining bugs. Of course, there were lots of immediate feature enhancements that users requested that were implemented shortly after shipping.
WHAT IS A BUG?
This is the most important chapter in the entire book. The very simple question, What is a bug, actually has a very complicated answer. This chapter is devoted to answering that question. Because, until we know what a bug is, we don't have a chance of minimizing them.
A developer I know once said, "Bugs should not be called bugs, they should be called Massive Fuck-Ups [MFUs]." "Bug" connotes that some outside agency decided to infest your program with bugs and that if you live a clean life, and sacrifice small furry animals at the foot of your computer, they will go away.
MFUs exist because programs are written by people, and people make mistakes. The only way to eliminate MFUs is to go into your code, find the bugs, and fix them.
This is the most critical concept to understand (and the one most often blown off). You will write MFUs. You will sit down and with complete malice of forethought put MFUs in your code. Think about it - you know that you are the one putting the bugs in there. So if you sit down to code, you will be inserting some bugs.
And somebody needs to find them so you can remove them. No amount of designing, prototyping, CASE, reviewing, management, and so on, will avoid this.
This concept is important because it colors your approach to debugging your code. If you view mistakes as "bugs," you hope none are found. (You hope the good fairy came by, sprinkled pixie dust, and the bugs left.) If you view the mistakes as MFUs, you know they unquestionably exist, and you hope to find all of them so that they can be fixed.
It is critical that developers and managers feel good, not bad, if MFUs are discovered. They should worry if they don't find any. Rather than assuming your program works and waiting for someone to prove otherwise, a developer should assume it doesn't work and search desperately for the bug that will make it fail.
So, for the moment, you have to accept that you will create MFUs in your code (I sure manage to put a lot in my code). I do not know of any way to avoid that. The trick then becomes to find and correct them as painlessly as possible.
As a side note, the term "bug" is so firmly established in the lexicon of developers that I see no way MFU will replace it. However, I think it is important that you occasionally refer to bugs as MFUs to remind people that bugs are "intentionally" placed in the code due to a developer's mistake.
When developers insist that bugs are not MFUs, you should worry. Why? Because they have abdicated responsibility for ferreting them out and fixing them. This is when it's critical to remind them that they are MFUs. It's much harder for someone to avoid responsibility when are told there is an MFU in their code than when they are told there is a bug in their code.
So what is a bug? Well, if you run the program and it formats your disk (assuming you are not writing a format program), most people will agree that a bug did it. From this point on, opinions start to differ. I hear statements like: "No one uses that feature so it's ok that it will trash the hard disk"; "Just tell them to buy a parallel port printer"; "They can override the result so it's okay that it doesn't add up correctly", and "That's not a bug, that's a feature!" The same people who find this type of thing acceptable in the programs they write will turn around and categorize bad design in a program they bought as a bug.
By my definition, if a reasonable person would expect certain functionality, or for a program to work in a certain manner, and it doesn't—there is a bug.
Where bugs come from
How do bugs get into a program? Very simply: You put them there. With reckless disregard, you sit down and type some buggy code into your program. It does not sneak in on its own. You might mistype a line. You might use a wrong variable. You might copy over some code from elsewhere that doesn't quite work. In any case, it is YOU YOU YOU.
Every time you code, you insert more bugs. This is one of the dirty little secrets of programming. Programmers write code and create bugs every day. Good coders are generally really good at creating bugs. That way our employers have to keep us around to fix all of the bugs later (COBOL programmers learned this years ago).