Sponsored Link •
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:
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.
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.
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.
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.
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.
|Kevlin is an independent consultant and trainer based in the UK. His development interests are in patterns, programming, practice and process. He has been a columnist for various magazines and web sites, including Better Software, The Register, Application Development Advisor, Java Report and the C/C++ Users Journal. Kevlin is co-author of A Pattern Language for Distributed Computing and On Patterns and Pattern Languages, two volumes in the Pattern-Oriented Software Architecture series. He is also editor of the 97 Things Every Programmer Should Know site and book.|