Generality creep
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Mon Apr 1 23:22:40 UTC 2019
On 3/31/19 8:01 PM, Mike Franklin wrote:
> On Sunday, 31 March 2019 at 16:18:35 UTC, Rubn wrote:
>
>> Look at this comment as someone pointed out before:
>>
>> https://github.com/dlang/dmd/pull/8557#pullrequestreview-149952733
>
> Yes, Andrei's review was a bit too strong but he did change course later
> in that thread. Also recognize that the original author did not provide
> much motivation or justification (though, I'm guilty of that too).
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.
More information about the Digitalmars-d
mailing list