I tend to read a work-related book every few weeks or so, and take the occasional note or highlight. I figured putting these notes somewhere more accessible would be worth the effort for future me, and anybody else who may be interested. So, here’s my book review of The Practice of Programming.
The book focuses on insights you typically gain through practice, as opposed to learning them as part of a course at university. I’ve been programming for a little over fifteen years now, and while most of the material was not new for me, almost all of it triggered a distant memory of learning things the hard way: trying one wrong solution after another before arriving at the right one. In a way, this book could be called “Things You Wish They Taught You Back At University”. Definitely worth a read, even for the seasoned programmer.
While it was originally written at the very end of the last century, I found the book has aged quite well. The majority of the examples are in C, and I’m somewhat ashamed to admit that I had to skim them, as opposed to devour them — it’s been more than a few years since I did any serious C programming. Nevertheless, the code examples illustrate the lessons of the text well, and I didn’t feel like my rusty C skills prevented me from enjoying the book at all.
The book consists of 9 chapters, and I’ll breeze through them below.
Chapter 1 focuses on style. Programs written with good style in mind are easier to write, read, and debug; they are overall better than those written in poor style. Some of style is subjective and language-specific, but the chapter does a good job of presenting its lessons in a general way, allowing it to be applied to a variety of languages.
My favorite quotes:
It is an old observation that the best writers sometimes disregard the rules of rhetoric. When they do so, there is usually some compensating merit to offset the cost of the violation. Unless you are certain of doing as well, follow the rules.
Sloppy code is bad code — not just awkward and hard to read, but often broken.
Chapter 2 focuses on algorithms and data structures, reviewing basic data structures like arrays, lists, hashmaps and trees; and touching upon searching and sorting algorithms. Knowing the right algorithms and data structures goes a long way towards writing a good program.
Chapter 3 follows up by demonstrating these algorithms and data structures to write a Markov Chain. I was impressed by how accessible and self-contained the example was: it was interesting enough to make me want to learn what a Markov Chain actually did, and it was substantial enough to allow me to understand it sufficiently.
Chapter 4 focuses on library design by introducing a CSV parser, and demonstrating how the design evolves as interface considerations become more apparent.
It’s not usually until you’ve built and used a version of the program that you understand the issues well enough to get the design right.
Chapter 5 is all about debugging.
Debugging statements stay with the program. Debugging sessions are transient.
Resist the urge to start typing; thinking is a worthwhile alternative.
Chapter 6 is about testing. Testing has come a long way in the last two decades, and this chapter felt a little bit dated. It feels like it was written before things like unit testing, continuous integration and deployment became commonplace. Nevertheless, the chapter dips into the fundamentals of testing, the “what” and “why”, as opposed to “using which tool”, and I found it well worth the time.
Test code at its boundaries. Failures are most commonly found there.
Chapter 7 is about performance: getting the most out of the scarce resources you have available, be it computing power or memory.
The first principle of optimization is: don’t.
A fast program that gets the wrong answer doesn’t save any time.
Chapter 8 talks about portability: writing programs that can work in a variety of environment. Again, since the book was written at a time when C++ was growing, Java was young, and my favourite Python was still an infant, and many of the problems this chapter describes have since faded into obscurity. I found this chapter an invaluable insight into how difficult things we find simple now used to be. It gave me an increased appreciation of how far things have come since then.
Any successful program, by definition, gets used in unexpected ways and unexpected places.
Chapter 9 focuses on notation: specialized domain-specific languages that can simplify a task that would otherwise be difficult when tackled with more general languages.
The book finishes with a helpful collection of the rules it described.