A commenter on my post pre-announcing Why C++ Is Not Our Favorite Programming Language asked “esr, from the perspective of a graybeard, which chapters did you consider good and which chapters did you consider bad?”
(Technical note: I do not in fact have a beard, and if I did it would not be gray.)
Good question, and worthy of a blog entry. I was the first technical reviewer for the manuscript of this book back when it was in preparation — IDG published it, but I think it was passed to me through MIT Press. As I noted in the same comment thread, I worked hard at trying to persuade the authors to tone down the spleen level in favor of making a stronger technical case, but didn’t have much success. They wanted to rant, and by Ghod they were gonna rant, and no mere reviewer was gonna stop â€˜em.
I’ve thought this was a shame ever since. I am, of course, a long-time Unix fan; I’d hardly have written The Art of Unix Programming otherwise. I thought a book that soberly administered some salutary and well-directed shocks to the Unix community would be a good thing; instead, many of their good points were obscured by surrounding drifts of misdirected snark.
You can browse the Handbook itself here. What follows is my appraisal of how it reads 14 years later, written in real-time as I reread it. After the chapter-by-chapter re-review I’ll sum up and make some general remarks.
I have a lot of respect for Don Norman, but he did not write this on one of his better days. The attempts at intentional humor mostly fall flat. And “…now that’s an oxymoron, a graphical user interface for Unix” looks unintentionally humorous in 2008. Otherwise there’s very little content here.
Similarly unfortunate. Sets the tone for too much of the rest of the book, being mostly hyperbolic snark when it could have been useful criticism. Very dated snark, too, in today’s environment of Linuxes wrapped in rather slick GUIs. The anecdotes about terminal sessions on Sun hardware from 1987 look pretty creaky and crabby today.
The authors write: “It’s tempting to write us off as envious malcontents, romantic keepers of memories of systems put to pasture by the commercial success of Unix, but it would be an error to do so: our judgments are keen, our sense of the possible pure, and our outrage authentic.” I know and rather like some of the authors, so it actually makes me a little sad to report that fourteen years later, writing them off this way is easier than ever.
Dennis Ritchie’s rejoinder is still funny, and his opening and concluding words are still an accurate judgment on the book as a whole:
I have succumbed to the temptation you offered in your preface: I do write you off as envious malcontents and romantic keepers of memories. The systems you remember so fondly [...] are not just out to pasture, they are fertilizing it from below. [... Y]our book is a pudding stuffed with apposite observations, many well-conceived. Like excrement, it contains enough undigested nuggets of nutrition to sustain life for some. But it is not a tasty pie: it reeks too much of contempt and of envy.
Chapter 1 – Unix: The World’s First Computer Virus
About equal parts of history and polemic, history not new, polemic cleverly written but not very interesting once you get through chuckling at the verbal pyrotechnics. The stuff on the standards wars is really dated now.
And no mention of Linux, which had just acquired TCP/IP support the year this was written and already had a thriving community. No one can blame the authors for not foreseeing 2008, but it’s as though they were mentally stuck in the 1980s, oblivious to the reality of 1994.
Chapter 2 – Welcome, New User!
There is some fair criticism in here. Yes, Unix command names are cryptic and this is a UI issue — mitigated a lot in 2008 by the presence of GUIs that no longer suck, but still an issue.
Quality of documentation still ain’t so great, and comprehensible and useful feedback when commands fail is something Linux applications could stand to be a lot better at. But these are problems almost everywhere, not just in Unix-land; it seems a bit unfair to reproach Unix for special sinfulness on their account.
On other points they do less well. “Consistency and predictability in how commands behave and in how they interpret their options and arguments” sounds very nice, but the first part is impossible (different commands have to behave differently because they solve different problems) and the second is more a gripe about shell wildcard expansion than anything else. Sorry, no sale; it’s too useful. If you don’t like the way
rm * works, go fire up a GUI file manager.
Then there’s a lot of flamage about Unix developers being supposedly content to write shoddy programs. Neither true nor interesting, just more hyperbolic snark obscuring the points on which they have a point.
There are some good nuggets in this chapter, but on balance digging through the excrement to find them does not seem worth it.
Chapter 3 – Documentation? What Documentation?
Yes, man(1) is still clunky and man pages are still references, not tutorials. This isn’t news in 2008, and wasn’t in 1994, either. The difference is that in 2008 the man pages style they’re excoriating is less of a blocker; we have the Web and search engines now.
Their fling at “the source code is the documentation” has got some unintentional irony since open source happened. Gripes about obsolete shells don’t add much, if anything, to the discussion.
Much that’s true in this chapter, but almost nothing that’s still useful or novel in 2008.
Mail: Don’t Talk to Me, I’m Not a Typewriter
This is mostly a rant against sendmail. Most of the criticism is justified. A lot of Linux distributions default to using Postfix these days, and the percentage is increasing; end of story.
Chapter 5 – Snoozenet: I Post, Therefore I Am
USENET is not exactly dead, but these days it’s mainly a relay channel for p2p media sharing and porn. There’s some stuff in this chapter of interest to historians of hackerdom, but nothing relevant to current conditions.
Chapter 6 – Terminal Insanity:
This chapter has dated really badly. To a good first approximation there simply aren’t any actual VDTs any more; one sees a few on obsolete point-of-sale systems, but that’s about it. It’s all terminal emulators or the OS console driver, they all speak VT100/ANSI, end of story, end of problem.
There’s an attempt at an architectural point buried in the snark. Yes, it would have been really nice if Unix kernels had presented a uniform screen-painting API rather than leaving the job to a userspace library like curses(3). But — and I speak as an expert here, having implemented large parts of ncurses, the open-source emulation of it — moving all that complexity to kernel level would basically have solved nothing. The fundamental problem was that Unix (unlike the earlier systems these guys were romantically pining for) needed to talk to lots of VDTs that didn’t identify themselves to the system (so you couldn’t autoconfigure them) and the different VDT types had complicatedly different command sets. The stuff that curses did had to exist somewhere, and its capability databases; putting it in a service library in userspace at least guaranteed that bugs in this rather tricky code would not crash the system.
But this is yesterday’s issue; the VDT is dead, and the problems they’re griping about dead along with it.
Chapter 7 – The X-Windows Disaster
This chapter begins unfortunately, with complaints about X’s performance and memory usage that seem rather quaint when comparing it to the applications of 14 years later. It continues with a fling at the sparseness of X applications circa 1990 which is unintentionally funny when read from within evince on a Linux desktop also hosting the Emacs instance I’m writing in, a toolbar with about a dozen applets on it, and a Web browser.
I judge that the authors’ rejection of mechanism/policy separation as a guiding principle of X was foundationally mistaken. I argued in The Art of Unix Programming that this principle gives X an ability to adapt to new technologies and new thinking about UI that no competitor has ever matched. I still think that’s true.
But not all the feces flung in this chapter is misdirected; Motif really did suck pretty badly, it’s a good thing it’s dead. ICCCM is about as horrible as the authors describe, but that’s hard to notice these days because modern toolkits and window managers do a pretty good job of hiding the ugliness from applications.
Though it’s not explicitly credited, I’m fairly sure most of this chapter was written by Don Hopkins. Don is a wizard hacker and a good man who got caught on the wrong side of history, investing a lot of effort in Sun’s NeWS just before it got steamrollered by X, and this chapter is best read as the same bitter lament for NeWS I heard from him face to face in the late 1980s.
Don may have been right, architecturally speaking. But X did not win by accident; it clobbered NeWS essentially because it was open source while NeWS was not. In the 20 years after 1987 that meant enough people put in enough work that X got un-broken, notably when Keith Packard came back after 2001 and completely rewrote the rendering core. The nasty resources system is pretty much bypassed by modern toolkits. X-extension hell and the device portability problems the authors were so aggrieved by turned out to be a temporary phenomenon while people were still working on understanding the 2D-graphics problem space.
That having been said, Olin Shivers’s rant about xauth is still pretty funny and I’m glad I haven’t had to use it in years.
Chapter 8 – csh, pipes, and find: Power Tools for Power Fools
Of the “plethora of incompatible shells” they anatomize in the first part of this chapter (including the csh in the chapter title), most are basically dead; the bash shell won. Accordingly, a lot of this chapter is just archaeology, known to old farts like me but about as relevant to present-day Linux or Unix users as Ptolemaic epicycles.
The portability problem in shell programming is almost, though not quite, as historical now. Languages like Perl and Python have replaced the kind of fragile shell scripting the authors fling at — in fact, that’s why they’re called scripting languages. The authors anticipated this development:
At the risk of sounding like a hopeless dream keeper of the intergalactic space, we submit that the correct model is procedure call (either local or remote) in a language that allows first-class structures (which C gained during its adolescence) and functional composition.
I give them credit, they were right about this. It seems curious, though, that they exhibited no knowledge of Perl; it had already been supplying exactly this sort of thing in public view for some years in 1994.
The end-of-chapter rant on
find(1) is still funny.
Chapter 9 – Programming: Hold Still, This Won’t Hurt a Bit
It is a shame that the authors are so quick to dismiss the Unix toolkit as a primitive toybox in this chapter, because that jaundiced error gives Unix programmers an excellent excuse to ignore the parts the authors got right. To point out a first and relatively minor example, the use of tabs in make really was a botch that ought to serve as a horripilating example to tool designers.
More generally, many of their points about C and its associated assumptions and toolchains are well taken. Yes, all those fixed-length-buffer assumptions are an indictment of weak tools and bad habits formed by them. Yes, LISP would have been a better alternative. Yes, exception-catching is an important thing to have.
We didn’t get LISP. We got Python, though. I could have cited Perl and Tcl, too, but they aren’t as close to being LISP (see Peter Norvig’s detailed argument that Python is Scheme with funky syntax.) My point here is not to advocate Python, it’s to observe that the Unix community noticed that C was inadequate and addressed the problem. If the statistics on Freshmeat are to be believed, more new projects now get started in scripting languages than in C.
Gradually, in a messy and evolutionary way, the Unix community is teaching itself the lesson that the authors of this chapter wanted to give it. I agree with them that it could have happened faster and should have happened sooner.
I’d say this chapter had dated the least badly of anything in the book, if not for the next one.
Chapter 10 – C++: The COBOL of the 90s
Though out of date in minor respects (C++ got namespaces after 1994, and the authors couldn’t address templates because templates hadn’t been added yet) this chapter remains wickedly on target. The only major error in it is the assumptions that C++ is in the mainline of Unix tradition, was gleefully adopted by Unix programmers en masse, and is therefore an indictment of Unix. Language usage statistics on open-source hosting sites like SourceForge and Freshmeat convincingly demonstrate otherwise.
Chapter 11 – System Administration: Unix’s Hidden Cost
This chapter is a remembrance of things past. When it was written, people still actually used magnetic tape for backups. It is probably the most dated chapter in the book.
In 2008 my septaguinarian mother uses a Linux machine and, after a handful of calls during the getting-used-to-it period, I’ve gotten used to not hearing about it for months at a time. Enough said.
Chapter 12 – Security
Many of the technical criticisms in this chapter remain valid, in the sense that Unix systems still exhibit these behaviors and have these vulnerabilities. But on another level the chapter is suspended in a curious vacuum; the authors could not point to an operating system with a better security model or a better security record. They didn’t even try to write about what they imagined such a system would be like.
The contrast with Chapters 9 and 10 is instructive. Many of the authors come from a tradition of computer languages (LISP, Scheme, and friends) that were in many and significant ways superior to Unix’s native languages as they existed in 1994 (the gap has since closed somewhat). They knew what comparative excellence looked like, and could therefore criticize from a grounding in reality.
There is no corresponding way in which the authors can suggest Unix’s security model and tools could be fundamentally improved. That’s because, despite all its flaws, nobody has ever both found and successfully deployed a better model. Laboratory exercises like capability-based OSes remain tantalizing but not solutions.
The correct rejoinder to this chapter is: “You’re right. Now what?”.
Chapter 13 – The File System
Most of the sniping about the performance and reliability of Unix filesystems that is in this chapter is long obsolete. We’ve learned about hardening and journaling; the day of the nightmare
fsck session is gone. The gripes about unreliable and duplicative locking facilities have also passed their sell-by date; the standards committees did some good work in this area.
The authors’ critique of the unadorned bag-of-bytes model is not completely without point, however; as with languages, some of the authors had real-world experience with systems supporting richer semantics and knew what they were talking about.
Some Linux filesystem hackers seem to be groping towards a model in which files are units of transportability that can be streamed, but internally have filesystem-like structure with the ability to embed metadata and multiple data forks. Others have experimented with database views a la BeOS.
There is probably progress to be made here. Alas, it won’t be helped by the authors’ persistent habit of burying an ounce of insight in a pound of flamage.
Chapter 14 – NFS: Nightmare File System
Some of the specific bugs described in this chapter have been fixed, but many of the architectural criticisms of NFS made here remain valid (or at least were still valid the last time I looked closely at NFS). This chapter is still instructive.
Summing Up: What’s Still Valid Here?
The original question was: “which chapters did you consider good and which chapters did you consider bad?”. Let’s categorize them.
The worst chapters in the book, at least in the sense of being the most dated and content-free for a modern reader, are probably 11 (Administration), 5 (Snoozenet), 6 (Terminal Insanity), 4 (Mail), and 1 (Unix: The World’s First Computer Virus) in about that order of worst worst to least worst.
The chapter with the soundest exposition and the most lessons still to teach is certainly 10 (C++), followed closely by 14 (NFS).
A few chapters are mostly flamage or obsolete but have a good lesson or two buried in them. In rough order of descending merit:
The authors were right to argue in chapter 8 that classic shell scripting is fragile and rebarbative, and should be replaced with languages supporting data structures and real procedural composition; this has in fact largely come to pass.
The knocks on C in Chapter 9 (Programming) were justified.
The objections to the pure bag-of-bytes model in Chapter 13 (The File System) should provoke a non-dismissive thought or two.
- At the bottom of this heap are the few nuggets in Chapter 2 (Welcome, New User!) about spiky command names and proliferated options.
Some chapters tell us things that are true and negative about Unix, but merely rehearse problems that are (a) well known in the Unix community, and (b) haven’t been solved outside it, either. It may have made the authors feel better to vent about them, but their doing so hasn’t contributed to a solution. I’d definitely put 12 (Security) and 3 (Documentation? What Documentation) in that category.
Chapter 7 (The X-Windows Disaster) is the hardest for me to categorize. There’s still ugliness under the covers in some places they mention, but I think they’re mistaken both in asserting that the whole system is functionally horrible and in slamming the architecture and design philosophy of the system.
More than ever I see this book as a missed opportunity. The 14 years since 1994 has been enough time for useful lessons to be absorbed and integrated; if all the chapters had been up to the level of 10 or 14, we might have better Unixes than we do today. Alas that the authors were more interested in parading some inflammatory rhetoric than starting a constructive conversation.