Welcome to Duncan White's Practical Software Development (PSD) Pages.
I'm Duncan White, an experienced and professional programmer, and have been programming for well over 20 years, mainly in C and Perl, although I know many other languages. In that time, despite my best intentions:-), I just can't help learning a thing or two about the practical matters of designing, programming, testing, debugging, running projects etc. Back in 2007, I thought I'd start writing an occasional series of articles, book reviews, more general thoughts etc, all focussing on software development without all the guff.
Book Review: The Practice of Programming
Authors: Brian Kernighan and Rob Pike Publisher: Addison-Wesley, Inc 1999. ISBN: 0-201-61586-X. Info: 267 pages; $49.99
Kernighan and Pike are two of the world's great practical computer scientists, with a reputation second to none. As we'd expect of two luminaries of the Bell Labs Unix world, in this book they write lucidly, distilling two lifetimes' experience of programming into their main themes of simplicity, clarity and generality.
After a useful introductory discussion of programming style - making the useful point that bugs often lurk in non-idiomatic stylistic constructs that skilled programmers don't recognise - they really hit their stride with a superb chapter on algorithms and data structures. In about 25 pages, they cover arrays (sorting, searching, growable arrays in C, C++ and Java), lists, binary trees and hash tables, making good use of function pointers (i.e. higher order functions) as they go - for example, when walking a tree or list, you should be able to specify the per-element operation you wish to perform. They also introduce O() notation, memory allocation and deallocation issues, tree traversal orders, and even some basic program transformation (turning tail recursion into iteration). Wow!
They continue, emphasising the importance of building a simple prototype implementation, and designing your data structures first, and letting your algorithms follow. As a strong data structures man myself, they're preaching to the converted! Via worked examples in several languages, they clearly expose every detail of their chosen problems with clarity and style.
Next, Kernighan and Pike tackle the importance of good interface design, discussing the design of - and then building - a general purpose CSV library in several languages. Although well presented with some style, and making some good points, I was a little concerned to see that the C interface they ended up with did not provide a function to free() the storage allocated, nor did it allow a line read from another source to be split later into CSV fields. Hmmm...
Excellent chapters on debugging and testing follow. They present a fruitful metaphor - debugging as puzzle-solving - and show several creative debugging strategies, ranging from teddy bears to numerology (a very subtle point!) and drawing pictures. I loved their advice to tell it to the Teddy Bear on page 123, which is very similar to Rubber Ducking from the Pragmatic Programmer. They are very strong on boundary checking, incremental testing techniques, and share with the Pragmatic Programmer a systematic testing approach (covering assertions, defensive programming, pre and post conditions, scaffolding and test automation). They stress the core point that you can only run tests automatically if each test knows the correct answer so that some scaffolding can call the test, compare the correct answer to the one generated and report test failures - rather than just produce pages of output for a human to read. One of my favourite sections covered stress testing - deliberately trying to find buffer overflows by thinking about likely edge cases and maliciously engineering bizarre test inputs.
Their next main topic is performance and optimization, they have a wealth of experience here and give really clear practical examples of how they have, over their long careers, optimized code when it matters. I particularly like their discussion of the numerology of profiling - how none of the numbers of calls produced by profiling tools are random, they all mean something and a smart profiler can deduce a lot from their inter-relationships. This is a powerful and subtle point that is very rarely stressed. They cover both time and space optimization well, and finally pay due homage to their Bell Labs colleague, and king of program optimization, Jon Bentley - who wrote the excellent Programming Pearls - review here books.
After a slightly dull chapter on portability, containing the surprising advice to avoid conditional compilation wherever possible, they close with a fantastic chapter - I wished it had been longer - covering the use and design of special notations (printf format prints, binary packing strings and regexes), little languages, programmable tools and programs that write programs. When discussing regexes, they introduce a simple 30-line library which implements a simple but powerful regex subset - you'll never have an excuse for embedding plain text searching in even the simplest application in future! They show some really clever examples of table-driven programming, where the data structures contain function pointers and the main program is just an interpreter's table-lookup-and-call-function loop. They discuss interpreters, compilers and virtual machines - developing an example doing expression evaluation via simple stack machines - and end up showing an on-the-fly code generator can turn an interpreted sequence of calls into machine generated code which is then executed directly.
Finally they collect all their wise sayings, rules and guidelines from the book into an appendix. There is, of course, quite a bit of overlap with Hunt and Thomas' The Pragmatic Programmer where they do exactly the same, but that's all to the good. We've already mentioned Kernighan and Pike's "tell it to the Teddy Bear" - aka Hunt and Thomas' "Rubber Ducking" - but there are several other examples. Picking just one, p238's exhortation to have a "single point of truth" and automatically generate all related forms from that is surely the same as Hunt and Thomas's "Don't Repeat Yourself" principle.
In summary, I strongly recommend both the Practice of Programming by Kernighan and Pike, and The Pragmatic Programmer by Hunt and Thomas. The Pragmatic Programmer is slightly more modern in style, and has a better collection of Tips, but Kernighan and Pike more than hold their own overall, win on performance optimization, and make some original points along the way.
In writing this review, I've come across the tPoP website at Bell Labs, which I thoroughly recommend, and stumbled across the following war story that didn''t make into tPoP - well worth a read!
firstname.lastname@example.org Back to my Practical Software Development Top Page. Written: Sept 2013