The primary purpose of the Data statement is to give names to constants; instead of referring to pi as 3.141592653589793 at every appearance, the variable Pi can be given that value with a Data statement and used instead of the longer form of the constant. This also simplifies modifying the program, should the value of Pi change.
—Fortran manual for Xerox Computers
Most developers consider debugging a necessary but unpleasant duty—the real fun is in the initial design because it's always more fun to write original, new code than to debug crusty, old code. That's a perfectly reasonable attitude, and I often feel the same way. It would be great if we lived in a world where code worked perfectly the first time. But we don't. Debugging will continue to seep up a large percentage of the development cycle for as long as humans are writing code.
I hope you've found the debugging techniques in this book useful. I hope you've learned tools to use in those situations when brute-force debugging is just too time consuming, and I hope you've gained a better understanding of those situations when brute-force debugging is exactly the right approach. Much of debugging is still pattern recognition—when you've seen (or read about) a similar bug before, it's much easier to know how to go about solving the bug. Practice and experience are always the best teachers, but we can still save ourselves a lot of frustration by learning from each other's bugs.
I'd like to share one last debugging story. Back when I was a grad student, I took a course in parallel processing, and wrote a parallelized chess program. Using complex analysis on multiple processors, my program evaluated millions of possible outcomes, ranked them in order of desirability, and then selected the move at the top of the list. With so much computational power, I was sure my program would beat any chess player in the world—except the first time I played it, it lost in only 8 moves. Clearly, the program was playing like an idiot, so with my scholarship at stake, I frantically searched for a way to improve the performance of my program.
Want to know the cause of my program's stupidity? After hours of searching, I found all my fancy parallel processing worked fine, and there was nothing wrong with my artificial intelligence, either. But I finally figured out the problem: When I ranked the list of moves in order of desirability, I had typed a ">" when I meant "<". So my list was sorted in reverse order of desirability—on each turn, my program correctly evaluated the relative strengths of every possible move… and then it chose the first item in the list, which was guaranteed to be the absolute worst possible move.
Sometimes, you have to just laugh at yourself and the bugs you wrote. Bugs aren't always as hard as you think, and some days, you'll write several thousand lines of flawless AI and parallel processing code, yet you won't even be able to sort numbers in the right order. Never take yourself so seriously that you lose the ability to explore whimsical theories like this. Once in a while, the simple theories may actually turn out to be correct! When you're stuck on a bug, do something ridiculous. It probably won't help, but it'll break the monotony and get your creative juices flowing again. That is, unless you get lucky, and the ridiculous idea actually does help….
May all your bugs be shallow. May all your crashes be easy. May all your customer issues be simple to reproduce, and may all your compilers never be buggy. May all your bugs be caught by testers before the code ships. And last but not least, may all your lists be sorted in the right order! Take care, and happy debugging.