Joel on Software
Yet Another Book Review
J. L. Sloan
Joel Spolsky is a hardened veteran of several campaigns in the software wars. He was on the Excel team at Microsoft. He worked for an internet startup. Now he runs his own successful software company.
Since about 2000 Joel has written an influential, and occasionally controversial, weblog, Joel on Software (http://www.joelonsoftware.com). The contents of his blog range from thoughtful treatises on software marketing strategies, to techniques for writing better code, to rants and raves where he names more names than I personally would feel comfortable doing in today’s litigious climate. That’s probably why Joel is writing a very popular weblog and I am not. The one common theme that runs through all of Joel’s essays is that they are frequently hysterically funny, typically at the expense of other hapless individuals or companies. Joel is not afraid to cite specific bad examples of what not to do. We should all be glad he has not turned his attention to the telecommunications industry (although he did write an essay on the joys of getting network and telephone service to his offices in New York City).
I discovered Joel’s blog while researching Robert Austin’s book, Measuring and Managing Performance in Organizations (Dorset House, 1996). Austin’s now famous book on measurement dysfunction was widely cited in many of the references I was reading at the time on software engineering and software development management. As the victims of the subsequent talks I have given on this book will recall, I found Austin’s ideas to be both intriguing and challenging in that they caused me to question some cherished beliefs. Further research was called for to determine if I was onto something really interesting, or if I was just being a fan boy and the author was full of crap. (It usually turns out to be some of both.) One of the articles that I turned up was a review of Austin’s book by Joel Spolsky.
Some of Joel’s better blog entries have been consolidated into a book by the same name, Joel on Software (Apress/Springer-Verlag, 2004). The forty-five essays in the book have been edited to offer a more coherent flow, and too allow forward and backward references to related material. The book is divided into four sections. The first is on practical aspects of being a better software developer. The second is on managing software developers and the development process. The third is a more general collection but is largely about software marketing strategy. The last, and least useful to me, was a series of essays on Microsoft’s .NET product, something which apparently figures prominently into the commercial web tools that Joel’s company, Fog Creek Software, produces.
Like Austin’s book, I found several ideas in Joel’s essays to challenge my own beliefs. One must be careful though in tossing out hard won experience. In his essay “Five Worlds”, Joel notes that software development is divided into roughly five different worlds, each with its own rules and culture.
“Shrinkwrap” is software that is sold in boxes at CompUSA or downloaded off the internet. It has millions of users and must run on as a generic a platform as possible to insure a broad user base. Shrinkwrap software is more or less in eternal development. Existing features must be refined and new features added to battle off competitors and to insure future revenue by enticing users to upgrade.
“Internal” is software that is developed for a specific internal application. Since there is really only one user of the software, there is no market pressure to improve it. Development tends to grind to a halt when the software is “good enough”.
“Embedded” software must be developed to a much higher quality standard. Even though it may be capable of being upgraded, it frequently is not. I’m reminded of the hassles I’ve had trying to upgrade various consumer devices such as MP3 players. Also, the limited interface to the device means workarounds to bugs may not be possible in the field.
“Game” software is unique for two reasons. Only “hit” games are really profitable, so a game developer must release a portfolio of games so that the very few hits make up for the more numerous bombs. The other issue with games is that they really are never upgraded.
Finally, “throwaway” software is that which is written to solve some immediate problem. It has no life cycle. For example, code written to convert files from one format to another may be used just once, until all the files have been converted. (I once developed tools to convert hundreds of thousands of files from the various IBM VM formats to something more palatable to UNIX languages. These were files accumulated in a petabyte-scale mass storage system over the span of a decade. Most of them were the output of supercomputer models and could not be recreated. Since the VM system was going away, there would be no second chance. The VM formats were not documented, so I had to reverse engineer the VM source code written in IBM assembler. I also learned a lot about UNIX file formats. As important this all was, I bet the source code for those tools does not even exist anymore.)
I found a lot to think about in this fairly simple software classification. Joel lives in the “shrinkwrap” world. The successful processes and techniques in his world might not work in my world. The other thing I thought about is that CM doesn’t quite fit in any of these worlds, although “embedded” is probably the closest. So maybe Joel’s taxonomy is a little coarse.
In “The Joel Test: 12 Steps to Better Code” he outlines the basic processes and tools every software developer should use and have at their disposal.
1. Do you use source control?
2. Can you make a build in one step?
3. Do you make daily builds?
4. Do you have a bug database?
5. Do you fix bugs before writing new code?
6. Do you have an up-to-date schedule?
7. Do you have a specification?
8. Do programmers have quiet working conditions?
9. Do you use the best tools money can buy?
10. Do you have testers?
11. Do new candidates write code during their interview?
12. Do you do hallway usability testing?
You the reader will probably not be able to avoid comparing this list to our own CM processes. It would be interesting to compare notes on this topic. Some of this, like “hallway usability testing”, is really only applicable if you are writing user-facing software, and in the CM process would have to be done by systems engineers. (As I’ve said before, translating ATM CES trunks would fail this test.)
In “Hard-Assed Big Fixin’”, Joel makes three points. “Make sure you find out about the bugs.” He recommends shrinkwrap-centric techniques for this, like automatic bug reporting when good software goes bad. But our own MR database is a form of this. “Make sure you get economic feedback.” He recommends charging the cost of a technical support call to the business unit that produced the code. This is an interesting idea in our own world. Maybe we already do this. But if we don’t, doing so would certainly alter the basic economics of software development. “Figure out what it’s worth to you to fix them all.” Joel admits that some bugs are not worth fixing. The cost of fixing the bug will be greater than the revenue gained or retained by having it fixed. But he argues that unless you know the economic cost of having a bug, it is hard to know the return on investment of fixing it. Much of the ROI lies in less tangible ideas like the perception of quality among your customers.
“Biculturalism” discusses the difference in cultures between the Windows world and the UNIX world. He cites from Eric S. Raymond’s book The Art of UNIX Programming (Addison-Wesley, 2003) (I have this), comparing Raymond’s UNIX-centric design culture with the Windows design culture. Joel remarks that UNIX applications tend to be written for other UNIX developers, while Windows applications are written for “Aunt Marge”, a naïve at best computer user.
They really are two completely different cultures. UNIX applications tend to remain silent until they have completed. Windows applications display a progress bar. UNIX applications have interfaces usable by other applications, including scripting languages; a GUI interface might be tacked on top. Windows applications are primarily GUI based; an API might be tacked on the side. (I’ve remarked that UNIX interfaces look like they were designed by a lot of graduate students that never talked to one another. Mostly because that’s exactly how they were developed. Windows applications, and Mac ones to boot, tend to have similar look and feels thanks to a common GUI toolkit on each platform.)
Joel remarks that neither approach is wrong. It is just a result of the cultures of each system. It will no doubt occur to you the reader that this may have more than a little to do with Linux’s incursion into the server arena while it has mostly failed on the desktop. (I use a Windows XP laptop as my desktop here in the palatial Digital Aggregates corporate headquarters. I also run Linux on a second laptop… which I use as a server. Using it directly is still just too painful.)
In the essays “Incentive Pay Considered Harmful” and “Measurement” (the review of Austin’s book), Joel tackles an issue you the reader can probably appreciate. He cites Alfie Kohn’s classic Harvard Business Review article “Why incentive plans cannot work” (HBR, September 1, 1993) (I have this):
“…at least two dozen studies over the last three decades have conclusively shown that people who expect to receive a reward for completing a task or for doing that task successfully simply do not perform as well as those who expect no reward at all.”
Those forced to listen to my talks on measurement dysfunction will recognizes this as the difference between extrinsic and intrinsic motivation.
He also cites material from another book I can recommend, Tom DeMarco and Timothy Lister, Peopleware: Productive Projects and Teams (Dorset House, 1999) (I have this too). DeMarco and Lister argue that regular performance reviews do more to drive wedges between team members than to improve productivity.
However, while I agree with the points here that Spolsky, DeMarco and Lister are making, I have to admit that none of them are very good at explaining just exactly what you should do instead. This is probably one of the reasons I have gotten out of management on three different occasions. Leadership I grok. Management remains a mystery to me, and, apparently, if my own experience is any indication, to most other managers.
I won’t describe the essay “Top Five (Wrong) Reasons You Don’t Have Testers” in any detail because, well, we have testers. Pretty darn good ones to boot, in my own experience. But it is worth mentioning that Joel says do not try to use programmers as testers. The skill sets are completely different. “I’ve seen a lot of this. Programmers do not make good testers, and you’ll lose a good programmer, who is a lot harder to replace.” Given our current perceived devaluation of good programming skills (while at the same time bemoaning the quality problem in the CM code base), maybe the “lot harder to replace” isn’t really felt to be an issue. Joel does promote offering interested testers a career path into development, which I agree with.
“Human task switches considered harmful” argues, with mathematical support, that it is probably more efficient to perform development tasks serially than in parallel. Anyone who has spent more time just keeping track of what is on their plate instead of actually accomplishing work will find no surprises here.
In “Things you should never do, part one”, Joel claims the single worst strategic mistake any software company can make is to rewrite code from scratch. Somewhat to my surprise, I found myself agreeing with this. Joel isn’t saying that “refactoring” is a bad idea. But he does use case studies of real companies who decided to rewrite their cash cow software product from scratch, and didn’t ship a product for years. One thing he says which got an “Amen, Brother!” from me was “It’s harder to read code than to write it”. This is absolutely true, even if you wrote it yourself. I remember years ago I had a young developer I had never met before show up at my office door asking about some code I had written mumble mumble years ago. It was in IBM 370 assembler. I didn’t remember the code. Heck, I didn’t even remember the project. Yes, I could see that the code was written in my style, and it had my name in the comments. Honestly, I remembered that there was a time in my life in which I had written tens of thousands of lines of IBM 370 assembler code. But I had no idea what this stuff he had in his hand was even for. But thanks to years of experience reverse engineering other people’s code, some of it in languages I had never seen before, we figured it out together. Thank the Fates for good comments. My opinion, not necessarily Joel’s: doing maintenance on large software bases was a good way for me to learn what is good code and what is bad code.
“The Iceberg Secret, Revealed”: “Customers don’t know what they want. Stop expecting customers to know what they want. It’s just never going to happen. Get over it.” There are exceptions to this rule, but it’s more true in my experience than not. As someone once pointed out, if companies only developed what customers wanted, the cellular phone would never have been invented. There was no perceived market for what later turned out to be a multibillion industry. This is why (again, my opinion) you must do a certain amount of forward looking work unless your goal is to produce the same commodity as your competitors and acquire market share incrementally. And you must expect the majority of your FLW to not yield useful results.
In “The Law of Leaky Abstractions” Joel generalizes what every OO developer already knows: that when an otherwise good abstraction starts to leak, that is, the abstraction starts to fail and exceptions in the interface start to creep in, problems occur. For example, NFS makes remote files look and act like local files. Until the network goes down that is, and the remote files don’t look or act anything like local files. The NFS abstraction develops a leak. However, “All nontrivial abstractions, to some degree, are leaky”. I would claim too that if an abstraction has no leaks at all, it probably isn’t really an abstraction. It probably accurately describes something quite concrete. However, an abstraction with no leaks may be either too trivial or too detailed to be useful. So leaks are inevitable.
The essay “In defense of not-invented-here syndrome” Joel attacks code reuse. Yes, this hurt a little bit, even though I believe I have come to agree with his argument. He points out the reuse is frequently proposed by “architecture astronauts” that don’t have to deliver working code (ouch). And that dependencies in code, whether caused by reuse or not, lead to breakage. An example of this, albeit not from Joel, is the so called “brittle base class” problem, where a change in a base class breaks all the derived classes, often in subtle ways. He proposes reusing code where it makes sense, but if the code implements a core function, do it yourself. He recognizes (although not necessarily in this particular essay) that this is also the rule for when to outsource business functions and when not to. If you are a software development company and your revenue stream depends on developing software, do not outsource software development. Payroll, yes. Accounts receivable, yes. But not core business functions.
In a series of five essays on software business strategy, he compares the Ben & Jerry’s business model (lots of competitors, commodity product, no customer lock-in, slow and sustainable growth to acquire market share, corporate culture is important, if all fails you won’t lose too much money) with the Amazon model (no competitors yet, must rush to acquire market share at all costs before they show up, things are moving so quickly that corporate culture is impossible, you have a tiny chance to becoming a billionaire, a much larger chance of squandering hundreds of millions). He discusses the myth of bloatware: yes, Microsoft applications have grown a lot in successive releases, but given the reduction in the cost of processing power and memory, they’ve actually gotten smaller in terms of their “dollar footprint” (my term). He talks about the application of the microeconomic concepts of substitutes and complements to software development, and in so doing gave me some nomenclature for what I was trying to accomplish in the late lamented DETRE effort on the IPEI project: a substitute is a product you might by if the product you really wanted was too expensive; a complement is a product that you buy in conjunction with another product. “Smart companies try to commoditize their products’ complements.” I was trying to commoditize the embedded operating system, to lower the cost of application firmware. Too bad I was too ignorant at the time to see this. Joel points out that this is why companies support open source development: they are supporting the development of a complement to whatever product (typically hardware) they sell to generate revenue. (Joel isn’t too complimentary of Sun Microsystems, whose marketing strategy neither he nor apparently anyone else can quite figure out.)
I have described only a fraction of the material in the book. I can recommend Joel on Software, both the book and the weblog, as long as the reader keeps in mind that Joel is writing about his own specific world. His essays are both insightful and entertaining, even though they sometimes come across as more of a rant and rave (this is true of even the better ones).
(For a bibliography of references like this book and others that I have found useful, visit http://www.diag.com/ftp/Bibliography.doc.)