We all agree that we want our programs to be simple: in the memorable words attributed to Einstein, “as simple as possible, but no simpler”. Kernighan and Pike’s most recent book, 1999’s The Practice of Programming [amazon.com, amazon.co.uk], has three key words written on a whiteboard on its cover: Simplicity, Clarity, Generality; and the greatest of these is Simplicity.
But what is “simple”?
I thought, or rather assumed, that we all agreed on this. But I’ve had a minor epiphany in the last couple of days.
I’ve been reading Martin Fowler’s 1999 classic Refactoring: Improving the Design of Existing Code [amazon.com, amazon.co.uk], which I got largely on the strength of Steve Yegge’s super-enthusiastic review. Steve described it as “a wonderful book about how to write good code, and there aren’t many books like it. None, maybe.” So I was really keen to read this …
… and I have to say that so far, it’s been a big disappointment. I’m on page 169, which is less than half way through; but I’ve read all the discursive, expositional chapters, and enough of the Catalog Of Refactorings to have a good flavour of how the rest of it is going to be. And while I appreciate the clarity of thought that’s gone into both the ideas themselves and their presentation in the book, I can’t help noticing that nearly all of Fowler’s refactorings make the code more complicated by introducing more methods, more method invocations and more classes.
Chapter 1, (Refactoring, a First Example) is the most enlightening part of the book, because as usual an ounce of example is worth a ton of explanation. In this chapter, Fowler starts with a program to calculate rental fees in a video store (yes, this dates the book!) The program consists of three classes (Movie, Rental and Customer), but the first two of these are pure data classes, consisting only of constant definitions, data members and accessor functions — what we C programmers in fact call structs. The third class, Customer, has a couple of members and accessors, and a single method that actually does any work: statement(). That is not a particularly pleasant method, for sure, but it’s clear enough, and would be clearer still if clarified by some “micro-refactorings”. By the time Fowler has finished improving this program, the logic is split across seven methods in six classes (four of which form an inheritance hierarchy).
Now I am not saying that the revised code is not better in some ways. Certainly each method is easier to read than the big one we started with; and the allocation of responsibility is cleaner. But look at the cost: to understand how rentals are calculated, we now have to read six classes instead of one method; and because of Java’s dumb source-code conventions, those classes have to be in six separate source files. And I would rather read one method than six complete files, thanks very much.
It reminds me of the 1980s British comedy Yes Minister — surely the funniest show ever made about three middle-aged men in suits sitting around in an office talking about politics. Whenever Jim Hacker, the government minister, wants to slim down the Civil Service, his Civil-Service aide Sir Humphrey Appleby responds by recruiting additional civil servants to form committees whose task is to look into the possibility of setting up working groups with a remit to establish terms of reference for proposals to set up meetings to consider strategies for reducing the size of the Civil Service. In the same way, Fowler’s response to code complexity seems to be to introduce more classes and delegate the living heck out of everything.
What’s going on here? Is Fowler talking complete arsegravy? Am I talking complete arsegravy, which I admit seems more likely on the face of it? I think not, in either case. I think what we’re seeing is that this simplicity business is not as, well, simple as we’ve all assumed.
It’s just this: I’m coming to the conclusion that one man’s simple is another man’s complex. Fowler evidently finds it easier to read many small methods than a few larger ones; I find the opposite. Going further, my colleague Adam Dickmeiss seems perfectly comfortable with huge functions, so long as their complexity is limited in other ways (e.g. few temporary variables).
To put it another way, both Fowler and I would like, if we could, to minimise both the number of methods, classes and source files, and their length. But these two measures of complexity often have to be traded off, and for me, the former is most important; for him, it’s the latter. I’m not going to claim that I am right and he is wrong: I’m coming round to the idea that it’s a matter of individual aptititude. Some people are better at long-distance running and some at sprinting; some can appreciate the nuances of classical music and some can discern substance and meaning in punk rock; some programmers grok functional code and some imperative. In the same way, I think some programmers’ minds are wired for dealing with many small code-chunks (methods, classes, etc.) and some for grasping fewer large objects.
If I am right about this, then there are a few corollaries:
- We can stop fighting about which kind of code is better. If I ever meet Martin Fowler, I can peacefully buy him a drink (or, better, get him to buy me one). It may be that the which-kind-of-code-is-simpler argument is not much more meaningful than which colour is better, red or blue.
- We should think about whether it’s good to try to concentrate similar-aptitude people together on teams, so that they all pull in the same direction; or whether it’s better to have some many-small-methods jockeys mixed in with some few-large-methods people, so that the project benefits from multiple perspectives.
- If you do mix your teams up, then you need to beware of getting into a fruitless refactoring war, with one faction constantly attacking with Extract Method and Hide Delegate, and the other retaliating with multi-megaton loads of Inline Method and Remove Middle Man. (Now that I come to think about it, I’ve been in wars like this without even realising it.)
Actually, I sort of hope I am wrong. I think there is something appealing about the idea of One True Way of writing simple code, and I am loath to give it up. (Just so long as everyone is prepared to agree with my definition.) We’ve all seen plenty of code that is Just Plain Bad — that’s not at issue. But maybe there is a whole spectrum of ways to be good.
Update (28 March 2010)
The comments on this article have been particularly provocative, and I found myself wanting to write an immediate follow-up. So I did, and here it is.
Also: plenty of discussion of this article over on Hacker News. Total silence on Reddit at the time of writing.