Book Review


The Practice of Programming

reviewed by Dwayne Phillips


Introduction

Brian Kernighan and Rob Pike combine their efforts again on The Practice of Programming. This text provides "advice that will help you write better programs.'' I'll extend this by saying it will help you and me write better programs better. The authors want to pass on the lessons they have learned about programming over the years. These are the lessons that are not taught in a classroom. They are usually caught painfully on the job. The audience includes students; people who program at work, but not as the main part of their job; professional programmers; and software managers.

The themes of the book are simplicity, clarity, generality, and automation. Simplicity keeps programs small and manageable. Clarity keeps programs easy to understand. Generality produces programs that work well in many situations and are easy to adapt to new situations. Automation refers to letting the machine do the work — let programs write programs.

Contents

Kernighan and Pike's book contains nine chapters. These are:

1. Style,
2. Algorithms and Data Structures,
3. Design and Implementation,
4. Interfaces,
5. Debugging,
6. Testing,
7. Performance,
8. Portability, and
9. Notation.

The chapters contain code in C, C++, Java, Perl, and Awk. The text explains the code, so knowledge in all the languages is not necessary. Rules are given and explained in each chapter. The rules are repeated at the end of the book.

The style chapter contains tips that help make code easier to read for the writer and others. The chapter covers variable names, expressions, comments, and the like. The authors encourage being consistent, clear, and accurate. Good programming style must become a matter of habit.

The chapter on algorithms and data structures runs through searching, sorting, lists, and hash tables. These basics appear time and again in programming. The concept of "O-notation'' or "on the order of" is introduced. This permits comparing algorithms in light of the number of operations per element of data. This is the best method of comparing the computational efficiency of algorithms.

The design and implementation chapter discusses the concepts of style, algorithms, and data structures. The authors implement an algorithm in five different languages. This illustrates tradeoffs among languages and how the design remains the same regardless of which language is used. Kernighan and Pike emaphasize starting with a good data structure, then applying algorithms.

The interfaces chapter discusses how to create an inteface for software that other people can and will use. The issues include interface (how to describe your software), information hiding (what to show and what to hide), resource management (who will manage memory and other resources), and error handling (who will detect, report, and act on errors). This subject is not often touched in programming classes. It is, however, a critical subject in programming in the real world.

The debugging chapter is rare indeed. Everyone tells programmers to write code that does not need debugging. That is good advice; Kernighan and Pike give it; all programmers strive for it, but none of us achieve it. The authors provide ample advice.

Two items stick with me. First, use a debugger. This sounds obvious, but many people don't use debuggers. Second, when stumped with an error, try explaining it to someone else. Often, you get two sentences into your explanation, and there it is, the answer. The authors related the story of one programmer manager who used a teddy bear in her office. When programmers came to her with a problem, she had them first explain it to her teddy bear. Most of them discovered their problem while talking to the bear.

The testing chapter gives practical advice for individual programmers. This differs from most testing texts that discuss testing from the system perspective. The authors stress that you test to find your mistakes, not to show that you didn't make mistakes. Their tips include: test as you write; test in an orderly, organized manner; and automate tests as much as possible. They conclude with the simple advice that whatever you do about testing, do it.

Performance does not matter much to most programmers. The authors admit this openly, yet justify this unusual chapter well. Their first bit of advice is: don't optimize. Today's computer hardware is so cheap that if you have a problem, just buy more hardware. There are, however, cases where speeding execution and reducing memory requirements are necessary. The authors walk through a systematic approach to optimizing whatever you may need to optimize. The key is to keep the software as clean and clear as possible.

The portability chapter discusses how to write software that will run everywhere. (No, it is not a chapter about Java.) The authors first advise using a standard language and staying in the mainstream of the language. Other tips include hiding implementation details and putting everything that might change in one location. An interesting idea is to side-step byte order problems by using ASCII text for data interchange.

The final chapter is about notation or using the right language for the task at hand. Every language (C, Java, Perl, Awk, etc.) was created to do a job. No language fits every situation. The authors extend this idea by encouraging programmers to create their own little languages and notations to solve problems. An example of such notation is regular expressions (available in grep, Perl, Awk, and others). Regular expressions are not a language like C, but they are a notation that helps us solve problems.

Comments

This book will seem familiar to programmers who have lived in the Unix world. The rules and discussion will explain why Unix and Unix utilities are the way they are. This book summarizes what you have seen, so it is a good reference.

The material will seem quite different to programmers from the Windows and PC world. (If you don't recognize the names Kernighan and Pike, this means you.) The text contains short, text-based subroutines and programs. This type of code is unusual in the Windows and PC world. For this reason, this book is a must-read. It will expose you to new concepts and give you many time-saving ideas.

The authors and editor could have done a better job with the themes. The cover, preface, and epilogue give varying statements of the themes. These variations can cause some confusion among readers. This is a writer's complaint, and this does not detract from the value of the book.

I most appreciated this book for its sense of history. The authors have been involved in significant events in software during the past thirty years. They describe how many problems faced by programmers today have been faced and solved by programmers already. The accepted body of knowledge in the programming world is growing. The message is there are many useful solutions out there for you to use — free!

This is an excellent book for programmers and people learning programming. There is nothing new here. What is here are many pieces of good advice — advice that will help us write programs, advice that will keep us from wasting time, and advice that will allow us to enjoy our work.

Dwayne Phillips has worked as a software and systems engineer with the US government since 1980. He has written Image Processing in C, R&D Publications, 1994; and The Software Project Manager's Handbook, Principles that Work at Work, IEEE Computer Society, 1998. He has a Ph.D. in electrical and computer engineering from Louisiana State University. He can be reached at d.phillips@computer.org.