Artima Weblogs | Kevlin Henney's Weblog | Discuss | Email | Print | Bloggers | Previous | Next

Five Possible Things after Breakfast
by Kevlin Henney
June 23, 2003
Summary
We were in the pub when Charles posed an NP-hard problem: "How do you teach programmers style and elegance in code? I would like five points or properties that I can teach to my programmers." Trusty pints of Guinness in hand, Charles, Frank and I set about trying to find some kind of answer.

Five considerations. Four Green Fields. Three conference delegates. Two days into the conference. One pint of Guinness each. No partridges or pear trees in sight.

A recent discussion on programming style and effectiveness reminded me of an evening in Tampa, Florida, during OOPSLA 2001. Frank Buschmann, Charles Weir and I decided to forgo the pre-digested delights that Tampa had to offer us, seeking refuge, beer and conversation instead in an Irish pub recommended to us by another member of the patterns community, Alan O'Callaghan.

So what do three members of the patterns community talk about over beer? The usual suspects would be patterns, the conference, something technical, something non-technical or, one of the traditional pub pastimes, solving the world's problems. It turned out to be something technical. Charles posed an NP-hard problem: "How do you teach programmers style and elegance in code? I would like five points or properties that I can teach to my programmers."

Not a trivial question to answer, but thanks to the buzz of the conference  as well as the beer  it was a cause and challenge we felt we could rally round. A good hour, more beer, many doodles and much discussion later we arrived at the following:

'Nuff said.

2. Symmetry

Why is symmetry important? It is a simplifying assumption. It reduces the amount of information in a design by making it more regular. But surely some asymmetry has a pleasing effect? Of course, but if you do not have a backdrop of symmetry against which you can hang asymmetry, you have just have chaos. If you're going to paint, you need a canvas.

For example, symmetry suggests balancing any resource acquisition with a release, such as having a disposal method pair with a factory method. Java programmers may assume that garbage collection will take of everything for them. That is only true (up to a point) for memory. But it is not memory you got from the factory: you got a smart, managed resource object whose lifecycle details are encapsulated. When you're done, give it back, by allowing disposal either on the resource itself or through the factory. C++ programmers may presume that using delete will do everything for them. But who said that the object was created using new? That is the point of encapsulating object creation in a factory: encapsulation. And who says actually destroying the object is the right course of action for disposal? Encapsulation begets encapsulation. Assuming a symmetric design until proven otherwise can make a factory micro-architecture looser and simpler.

3. Spacing

Spacing refers to boundaries, separations, connections, etc. Spacing applies at the smallest level, e.g. indentation of source, as well as the largest, e.g. how interfaces are used to partition component "neighbourhoods" in a large system.

You want to make sure that your code is formatted with reasonable spacing, so that it does not look like line noise, but at the same time you don't want it drowning in space, so that readers should not find themselves scrolling up and down the screen to read what is in truth a blank screen punctuated with the occasional piece of code. When considering the big picture, you don't want hundreds of classes all cohabiting in the same space, undifferentiated and intertwined. They should be separated out into packages with the highest cohesion and lowest coupling that is reasonable.

4. Visibility

Or, put another way, intentionality. Software is effectively invisible, and software development is in part the art and craft of shaping the invisible. However, although mechanism transparency and information hiding are useful concepts, each concept must be visible at some level to be easy to understand. Outside a class you want representation decisions to be as invisible as possible; inside it you need for them to be visible so that you can understand them and the effects of changing them.

So, making things visible should be part of the disclosure of a well-written piece of code. This is not a matter of spelling things out on drool-proof paper, which goes against economy and emergence, but of adopting techniques that make the relationships between structures and rationale as clear as possible at the right level.

For example, adopting suitable idioms can make the intent of a piece of code more visible, whether it is choosing a more specific class instead of a plain int to express whole-value concepts or using a named constant to factor out a magic number. The same principle applies all the way up to the macro-architectural scale, so the explicit interfaces between components and choice of patterns used should make the intent and interconnections more visible.

5. Emergence

Simple rules or mechanisms can lead to profound and complex behaviour. In the real world we see this in the flocking of birds: (1) steer towards the average position of your neighbours; (2) adjust speed to match your neighbours; (3) don't bump into anything.

In software, not all the behaviour desired of a system has to be painstakingly and explicitly defined. Often behaviour arises out of the collaboration of parts, and the relationships between them, rather than the parts themselves. Many decisions do not need to be documented explicitly in code: polymorphism, function pointers, dynamic loading, etc, all offer reasonable alternatives to patchworks of special cases brought together in rambling if or switch statements. Emergence is not the same as magic  there should be nothing mystical in your code  but it may sometimes be in tension with the notion of visibility.

The Morning After

While I would not claim that these points, properties or principles are in any way final and definitive (recall their humble origins!), or indeed even meet Charles's challenge, I have found that they have provided a useful focus for discussion. They are qualities I have observed in much code that I would consider elegant.

However, the slippery and diverse nature of aesthetics pretty much precludes them from being thought of as rules ("Thy code shall exhibit the qualities of economy, symmetry, spacing, visibility and emergence, otherwise DLL-fire and damnation shall befall it!"). They are too abstract for such concrete causal dogma. They are also not specific enough or constructive enough to be seen as recommendations. A recommendation differs from a rule by being more of a guideline than a law of the code.

The five points are probably best classified as considerations. A consideration is a suggestion to take something on board and keep it in mind; it may (or may not) inform your design thinking rather than regimenting it. So that piece of code you were going to work on this morning? There's five possible things to consider after breakfast.

Talk Back!

If you'd like to be notified whenever Kevlin Henney adds a new entry to his weblog, subscribe to his RSS feed.