The paper argued that Unix and C have the characteristics of
viruses, and that in the evolutionary struggle among software designs
traits like implementation simplicity and portability which lead to
rapid propagation (infectiousness) are more effective than correctness
and completeness of the design. Gabriel came so close to anticipating
the ‘many-eyeballs’ effect on open-source software that
the open-source community retrospectively adopted him as one of its
theorists after 1997.
Less remembered is that the Gabriel's central argument was about
a very specific tradeoff between implementation and interface
complexity, one which rather exactly fits the categories we have
examined in this chapter. Gabriel contrasts an ‘MIT’
philosophy most valuing interface simplicity with a ‘New
Jersey’ philosophy most valuing implementation simplicity.
He then proposes that although the MIT philosophy leads to software
that is better in the abstract, the (worse) New Jersey model has better
propagation characteristics. Over time, people pay more attention
to software written in the New Jersey style, so it improves faster.
Worse becomes better.
In fact, the MIT and New Jersey philosophies have analogs as
conflicting tendencies within the Unix design tradition itself. One
strain of Unix thinking emphasizes small sharp tools, starting designs
from zero, and interfaces that are simple and consistent. This point
of view has been most famously championed by Doug McIlroy. Another
strain emphasizes doing simple implementations that work, and that
ship quickly, even if the methods are brute-force and some edge cases
have to be punted. Ken Thompson's code and his maxims about
programming have often seemed to lean in this direction.
The tension between these approaches arises precisely because
one can sometimes get a simpler interface if one is willing to pay
implementation complexity for it, or vice versa. Gabriel's original
example, about how system calls that do long operations handle
interrupts they cannot hold or mask, is still one of the best. Under
the MIT philosophy, the right thing to do would be to back out of
the system call and automatically resume it once the interrupt has
been handled; this is harder to implement but leads to a simpler
interface. Under the New Jersey philosophy, the system call would
return an error indicating that it has been interrupted and the
user must re-execute; this can be implemented far more simply, but
leads to a programming interface that is more difficult to use.
Both approaches have been tried. Old Unix hands will instantly
think of System-V-style vs. BSD-style handling of software signals;
the latter follows the MIT philosophy, while the former hails from New
Jersey. Underlying the choice between them is a pressing question
that has nothing directly to do with the software's infectiousness:
if your goal is to hold down total global complexity, where are you
most willing to pay to do that? Where
should
you
be most willing to pay?
One epochal example not mentioned in Gabriel's paper is from
distributed hypertext systems. Early distributed-hypertext projects
such as NLS and Xanadu were severely constrained by the MIT-philosophy
assumption that dangling links were an unacceptable breakdown in the
user interface; this constrained the systems to either browsing only a
controlled, closed set of documents (such as on a single CD-ROM) or
implementing various increasingly elaborate replication, caching, and
indexing methods in an attempt to prevent documents from randomly
disappearing. Tim Berners-Lee cut through this Gordian knot by
punting the problem in classic New Jersey style. The simplicity of
implementation he bought by allowing “404: Not Found” as
a response was what made the World Wide Web lightweight enough to
propagate and succeed.
Gabriel himself, while sticking with the observation that
‘worse’ is more infectious and tends to win in the end,
has publicly changed his mind several times about the underlying
complexity-related question of whether or not this is actually a good
thing. His uncertainty mirrors a lot of ongoing design
debates within the Unix community.
We cannot offer a one-size-fits-all answer. As with most of the
large questions in this chapter, good taste and engineering judgement
will demand different answers in different situations. The important
thing is to develop the habit of thinking carefully about this issue
on each and every one of your designs. As we have observed before in
discussing software modularity, complexity is a cost you must budget
very carefully.
[an error occurred while processing this directive]