Concision and expressivity in code

For one reason or another, I’ve looked a fair bit of other teams’ web server code recently - in Java/JSP and PHP. Now, as always, people write too much code. Almost always the result of a naive approach to solving a problem, combined with an insufficient comprehension of programming patterns and language idioms. My favourite was a page that appeared when looking at a server-side component in Java - it was a long method, but at one point when scrolling down this appeared:

                                                            }
                                                        }
                                                    }
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            }
        }
    }
}

That’s right - four closing braces, a break, eight more closing braces, another break, then - finally - four more closing braces. All beautifully formatted of course - I’m guessing the hapless developer just kept adding braces until Eclipse said they were done.

These experiences reinforce the thinking about Code Debt that Peter Marks and I have been developing. There’s an optimum point of code expressivity where the meaning is obvious, the code is clearly correct, and (in the words of The Programmers’ Stone), less places for bugs to hide.

(Apropos the Stone - is it me, or are the slashdot comments pointing out errors in the Quality Plateau example simply incorrect?)

Here’s another example - in JavaScript - from our SPA2008 session on Code Debt. We built some of the session around two alternative solutions to a progressive set of features being built on a simple function to convert a string from space-separated words into camel case. Both were built test-first (the same tests, of course) - the sad thing is, the “naive” solution can be (mistakenly) justified as “the simplest thing” in XP terms - but here “simple” means “the quickest thing I could do to get the tests to pass”. The final iteration of the problem in the “clean” branch uses JavaScript object literals to hold the functions that implement translating identifiers to and from a base representation as a list of words - it’s way shorter than the heavily procedural naive version, uses key aspects of the language and built-in classes effectively and appropriately, and is readily understandable and extensible:

function convertIdentifier(src, srcType, dstType) {
  var allWords = src.split(srcType.sepExp);
  var nonEmptyWords = allWords.filter(function(word) { return word != '';} );
  var correctCaseWords = nonEmptyWords.map(dstType.calcCase);
  var result = correctCaseWords.join(dstType.joinChar);
  return result;
}

var CI_TEXT = {
  sepExp: ' ',
  joinChar: ' ',
  calcCase: _toLower
};

var CI_CAMEL_UPPER = {
  sepExp: /(?=[A-Z])/,
  joinChar: '',
  calcCase: _toInitialUpper
};

var CI_CAMEL_LOWER = {
  sepExp: /(?=[A-Z])/,
  joinChar: '',
  calcCase: function(word, index) {return index == 0 ? _toLower(word) : _toInitialUpper(word);}
};

function _toLower(s) {
  return s.toLowerCase();
}

function _toInitialUpper(s) {
    return s[0].toUpperCase() + s.slice(1).toLowerCase();
}

Concision of this sort is often associated with higher-level languages (crucially, the presence of functions as first-class objects in the language makes a big difference - so think JavaScript, Ruby, Scheme, not Java, C++…). My favourite example of poetry in code at the moment is Haskell (though I’m sure some of the other functional languages match it for expressivity). Quicksort in Haskell is a direct implementation of the algorithm:

qsort []     = []
qsort (p:xs) = qsort [ y | y <- xs, y < p ] ++ [p] ++ qsort  [ y | y <- xs, y >= p ]

(If you don’t read Haskell - the two pieces of code in brackets are list comprehensions - read the first one as “the set of elements y, such that y is taken from xs and y is less than p. the argument to qsort is a list, split into a head element and a tail in the argument (p:xs). See the Literate Programming Wiki for examples of quicksort in many languages)

No Comments

Add your own comment...