Right Work

(Spring, 2019)

Several months ago, I ran across a post somewhere on the internet (I can’t remember where - maybe HackerNews?), that I really just want to re-broadcast here. I’m going to put this in the context of some of my own work and add some personal comments, but I’m not really trying to add any insight; the content stands on its own.

This short exposition was originally posted by Andrei Alexandrescu on the dlang forums while discussing some recent pull request activity and how to prioritize work and maintainers’ time.

Besides putting some needed perspective on the kinds of work that happen around software, I wanted to highlight these concepts to partially explain why I choose to do some of the work that I do. I used to get discouraged about those days where productivity seems to lag, but I slowly discovered that there was always worthwhile tasks to be done that required less ingenuity but were also unglamorous. After a while, I also started to notice that when enough of these get added up together, it can make the difference between a project that is pleasant to work in and one that always seems to be hitting some kind of kink or speed bump.

People who know me may have heard me refer to “laying bricks” or “being a bricklayer” in software projects. I am referring to things that should obviously get done, but are not the creative architecting types of tasks. Nor are these efforts typically seen as headline (i.e. resume/CV) worthy. Perhaps most tricky, bricklaying is hardly ever on the project’s critical path, so short-sighted project members and managers may have a difficult time with it.

I find that there is rarely a shortage of people wanting to work on greenfield development tasks or optimizing marquee features, but usually no one is jumping to improve testing or clear out compiler warnings. I enjoy filling these gaps because I see them as force multiplyers; removing small but universal hinderances to better quality software benefits everyone contributing to the project, whether or not they even care about these things.

The original text

At some point in the past, I had trouble finding the original text of the dlang forum post, and one of those times I went to an internet cache and copy-pasted the text for myself. If you are having trouble finding it at the original source, here it is as I copied it sometime in the spring of 2019. There is some minimal context included, but don’t get too hung up on the previous discussion that is being referenced.

Here is Andrei Alexandrescu’s post, originally at https://forum.dlang.org/post/q7u6g1$94p$1@digitalmars.com


Those were unnecessarily strong words.

Allow me to give a bit more context whilst clarifying I am not defending or condoning that attitude.

That comment came after a few phone conversations whereby Walter mentioned he has a deluge of pull requests to review. He said if he’s to spend due time on all of those, he’d be unable to do any work of his own. Those pull requests that have these things in common (note that some may not apply to the pragma pull request, I’d just wrongly put it in the same bin):

  • they are large
  • the improvement they bring needs arguing
  • their quality could be improved so they need careful review and a couple of passes of changes

This is what I call Good Work.

Good Work is often sizable in quantity, and is visibly the result of concerted effort by a competent person. Those unfamiliar with a codebase and with the subtleties of the task at hand cannot produce Good Work.

(Contrast that with Bad Work: by definition, it is easy to inspect and reject. It does not create a major slowdown in a project.)

Good Work is more often than not complex. Complexity is misrecognized as evidence of the complexity of the problem; the task was hard, the reasoning goes, because the solution is difficult in proportion.

Good Work begets more Good Work. Typically Good Work produces context, opportunity, and precedent for more of the same. The same reviewer who rubber stamped a piece of Good Work will have an idea how to produce more Good Work derived from it. The kind of environment where Good Work is revered encourages its creation, in a cycle that creates the illusion of progress. Because Good Work is complex, it produces “bug ripples” whereby increasingly complex Good Work fixes one bug but is liable to introduce others.

Good Work is difficult to argue against. The main argument in favor, which is very difficult to counter, is that Good Work is better than Bad Work and better than No Work. It is easy to create an opinion trend in favor of this or that Good Work.

However, there are problems with Good Work. The first one is scale: an accumulation of Good Work does not add up to Great Work. More often, the increasing entropy leads to the thermal death of the project.

An accumulation of Good Work is what leads to six nested calls in an advanced library to convert a string to an integer. Even if they are inlined away in execution, their smell persists.

An accumulation of Good Work is what leads to a multitude of “is this kinda sorta almost like-a string hey I really mean it this time quite like a string” tests, or “we must to add @trusted every five lines of code”.

The other problem of Good Work is that it takes the air out of the room, causing Great Work to suffocate. Good Work takes great effort to author, debate, review, debug, and maintain. All that takes away time and mental share that should go into Great Work instead.

Which brings us to Great Work.

Great Work solves difficult problems with a paucity of means; it is quintessentially and surprisingly /not/ proportional response. Because of that, it is often deceptively simple, but always in a way that is impossible to anticipate yet obvious in afterthought. Scala’s implicits and D’s static if are great work.

Great Work often reformulates an entire challenge to reveal false choices or artificial constraints. Alexander the Great figured it doesn’t matter how to get rid of the Gordian knot, so he cut it. While philosophers were still puzzling over The Ship of Theseus, Richard Feynman pointed out that the very notion of identity is ill-defined because a philosopher wouldn’t even be able to tell which atoms belong to a chair, and which don’t. Replacing complex type-based metaprogramming with trivial compile-time evaluation is great work.

Great Work is often recognizable to out-of-domain people, the person on the street. In contrast, Good Work has high-brow expertise as a prerequisite. Beethoven’s Fourth Symphony is a respectable repertoire piece for any Philharmonic, one that music aficionados would listen to with respect. I once saw a janitor, a little old lady with no previous exposure to classical music, crying when she heard Bach’s Air for the first time. Using the same programming language on the client and server, or at compile-time and run-time, or for computation and its constraints, is great work clear as rain. You don’t need to be an expert to appreciate that.

Great Work is what we should all aspire to. Great Work is the cure for Good Work.

This, however, brings up a question: it seems that Great Work is not really easy to do on a regular basis. What to do, therefore, on a “regular” day when inspiration doesn’t strike?

This brings us to Right Work.

Right Work is work that is undeniably, pound-on-the-table good, however unexciting or trivial.

Right Work will be silently appreciated by one’s peers as the incontestably right thing to do. Paying your rent, debts, and other bills is Right Work.

Right Work is not necessarily simple. Becoming a better spouse or teaching your kids that lying is not a good policy - that’s also Right Work.

In a software project, reducing the number of global variables is Right Work.

Making public data private is Right Work. (Careful, perversions are always possible. This is not Right work:

public int percent;

==>

private int _percent;
int percent() { return _percent; }
void percent(int p) { _percent = p; }

The obscure word “phronesis” - thanks Laeeth - should be a buzzword in software engineering circles.)

Reducing state and mutation is Right Work. That means adding the “immutable” qualifier to variables and the “pure” attribute to functions.

Making unsafe code safe is Right Work. That means inserting “@safe” wherever possible, and identifying the smallest “@trusted” primitives.

Replacing legacy pointer-and-length ad-hoc pairs with slices is Right Work. So is replacing a complicated unstructured loop with a structured foreach loop.

Most refactorings that meaningfully reduce the number of lines of code are Right Work. Of course, that could be perverted, too. I’m not talking more statements per line of code. I’m talking more /work/ per line of code.

Much Right work paradoxically requires less virtuosity than complicated artifacts of Good Work.

A successful software system is a construction of Great Work on a foundation of Right Work, with the inevitable Good Work here and there.

That’s where we want to be.