Beth Kjos

Earth-shattering project ideas. Resumes. Things in between.

Thoughts on Code Quality

I was frustrated at my own speechlessness when a colleague asked me what was wrong with a certain module which I’d spent an alarming fraction of the past week straining to comprehend. (Needless to say, I spent then next few minutes being gob-smacked by how completely differently the two of us seemed to see the module’s code quality.) That evening I resolved to give the man a proper answer regardless. In some sense, this page is that answer.

Perceiving Quality: an Introductory Allegory

In vino veritas.

In my neighborhood, good wine gets you drunk. In Millionaire Acres, good wine has a high numerical score from some oenological institute that I’ve never heard of.

I had a friend-of-a-friend in college who used to make trash-can wine in the dorm room closet. It had funny flavors, odd smells, unpleasant aftertaste, a cloudy appearance, and it left you with strange intestinal phenomena the next day, but boy oh boy it got you drunk.

I think, even in my neighborhood, that would be considered bad wine. Let me be clear: The Rubbermaid Brute that served as fermentation vessel was not the thing that made the wine bad. However, said sanitation equipment certainly did not help matters. Other contributing factors included poor temperature stability, slipshod procedures and equipment generally, dubious ingredients, hard water, and a general lack of concern for the experience of savoring a fine beverage. In that one brewer’s own opinion, he was making perfectly good wine: It got him drunk when he chugged it.

Objective Quality: Fitness for Purpose

It’s easy to dismiss the question of wine quality as a matter of taste, but there some things that we should all agree are bad wine. For instance, wine that makes people blind is terrible wine, regardless of how it may taste. Any objective measure of quality needs to take purpose into account.

The purpose of wine is manifold:

Wine can be measured by its ability to do any or each of those things. Wine which fails on too many counts is objectively not very good.

Desiderata

In his article What Does Good Code Look Like?, Jesse Hill gives brief but insightful commentary on the following desirable characteristics of good code:

To these I would add:

Rationale

I mostly subscribe to the Dijkstra school, which is a bit purist:

However, unlike Dijkstra (who infamously called software engineering “how to program when you cannot”):

From day to day we make our living by changing existing code. (Only rarely will that existing code be an empty module.) Activities involved in this task include:

Therefore, the elusive measure of code quality is whatever influences the cost of those activities on an ongoing basis. The same can be said of the quality of the development process overall.

An entire essay could be written about each point, and some of their consequences. I might do that someday. Today is not that day. Meanwhile, if you read Dijkstra, you’re off to a pretty good start. In particular, his class notes gives a pretty good overview (despite embedding some outdated cultural assumptions).

Techniques

Mark Jordan writes in How to actually write good code about a number of specific techniques. Among them are:

To these I would add:

Case Study: Short Methods

Once again, I begin with an allegory:

Search, and ye shall find no end of different ideas on how long a method may become before it must be broken up. It’s almost as if people believe method size determines how easy it is to work on code.

Probably the most extreme short-method coding is common in APL and its closest cousins. (If you’re curious, this book by Kenneth Iverson is the definitive source on APL.) In practice, though, most people find APL to be inscrutable. So instead, let me refer you to the book Thinking Forth, by Leo Brodie. It truly deserves to be considered a software-engineering classic.

Let me restate one of the design tenets from the Brodie book, gently adapted to the languages popular in industry today:

If you set out to write methods that clearly express both their intent and function, with but a single level of abstraction between the what and the how, then in consequence you wind up with short methods. You also end up with a lexicon of words related to the topic of … whatever it is your program or module happens to do. We do not set out to golf the code. Rather, we golf the level of effort required to understand and modify it.

Sometimes, during incremental maintenance, you find a method of such size and complexity that it is hard to comprehend. The time you spend trying to understand it anew will be much better repaid if you close the loop by casting your new comprehension in the form of a few well-chosen words added to the lexicon and corresponding adjustments to the original method to use the new words appropriately.

One Final Exhortation

Code as if your tired colleague will have to explain everything to a new-grad in six months, after you’ve had time to forget the details and stumbling blocks.