as someone with an affinity for the marriage of beautiful glittering abstraction and practical
results-driven application, I’ve always loved reading about the philosophy of programming
and software design.
As with all sorts of design, there are a number of esoteric and largely arbitrary prejudices
in the field that are simply artifacts of an effort to develop some kind of pragmatic
uniformity, to gently herd a bunch of creators who pride themselves on their originality
into anything besides roiling chaos.
But there are also ideas that seem to have widespread acceptance among programmers as
tapping into some deeper truth about what makes good code, guidelines and rules of thumb
that should be followed not out of some obligation to conform to the field’s standards, but
to make software that is more stable, less prone to bugs, more adaptive and functional.
Curiously, the principles themselves seem largely aesthetic in nature, prescribing a
specific flavor or style of coding that *feels* a certain way.
Park an experienced programmer in front of an amateur’s code, and you’ll likely get
an earful about how it’s “messy” or “unrefined,” maybe even “disgusting.”
These aren’t evaluations based on how well the code works - the judge in question might
not even know what the program does, but even so, more often than not, they can smell bad
programming.
As an engineer, I find that aesthetic bears a remarkable resemblance to ideals that I
try to build into physical objects.
It doesn’t seem totally crazy to imagine that there might be some useful, high-level
concepts that are shared in both disciplines or even among many disparate types of design.
For example, Once and Only Once is a common theme in programming, the idea that every
statement of a program’s desired behavior should only ever occur in a single place in
the code.
If you want a button that does X and a button that does X and Y, you don’t rewrite all
the same code for X for both buttons - the X behavior should appear Once And Only Once
in the program, and both buttons should point to that same location.
There are good practical justifications for this principle.
Perhaps most obviously, there’s an economy of effort and size - writing the same bit
of code over and over again is a waste of time and megabytes.
If you want to change that operation in some way, you only have to change it in that one
place, assured that all parts of your program that call for it will now call for the new
version, instead of having to troll through code to find every instance where you’re
trying to do X and update each accordingly.
It’s also much more legible when someone’s trying to read and understand your code to
see “do X here” than it is to parse all the nitty-gritty details of doing X every
time it pops up.
The idea of limiting the number of expressions of a given function has obvious parallels
in many different domains.
In engineering, the concept of fully constrained or overconstrained systems warns against trying
to define an object’s position in redundant ways that might conflict with each other - a
four-legged stool can rock back and forth if one of the legs is too long, while a three-legged
stool is always perfectly stable, because each of its six degrees of motion is restricted...once
and only once.
Many have experienced the frustration of not knowing which of several likely places houses
a certain object - is that marker in the knick-knack drawer or the random crap drawer?
It can also crop up in institutions, where it can be a chore to figure out who you need
to talk to because multiple departments overlap in some domain.
“Look, all I want to know is who I need to talk to to get the name on my account fixed.
What do you mean you’re not sure if that’s a customer service question or a technical
support question?”
Another example: in software, a “god object” is some part of a program that has grown so
deeply enmeshed and interconnected with everything else that deleting or changing it in any way
would be catastrophic.
Rather than sectioning off the program’s operations into small single-purpose modules
that can be managed independently, the large, complicated god object essentially coordinates
and processes every aspect of the program, seeing and knowing all.
This is a problem for several reasons.
It complicates any modifications a programmer might want to make, maybe rendering certain
changes impossible in the interest of preserving the god object’s basic structure and functionality.
It can be hard to parse all the different things that it’s doing when reviewing code,
rendering it unintelligible.
And it can be a little exhausting trying to tiptoe around a five-hundred pound gorilla
that has the ability to bring everything crashing down if it’s not carefully minded.
God objects can also be found in other fields, like philosophy, where they’re not always
gods, but simply key concepts or arguments upon which everything else in a system of
thought turns.
If you kick the verification principle out from under logical positivism, it turns out
the whole thing just collapses.
Micromanagers who insist on making all important decisions and hoarding all important information
are just begging to be hit by a bus, ruining their team’s chances at success.
The general consensus among programmers is that, wherever possible, functions should
be simple, light, and modular, a useful principle for all sorts of systems.
They also believe that, when they get too hairy, god objects should be grimly dismantled,
bit by bit.
Despite how labor-intensive it might seem, the effort is trivial compared to how much
time will be wasted trying to appease the damned thing in the long run.
In a similar vein, programmers have a particular appreciation for how greater functionality
isn’t necessarily an improvement from the perspective of the end-user.
The phrase “Worse is Better” is a tongue-in-cheek way of referring to this idea, suggesting
that a program that has fewer bells and whistles, that is, a “worse” program, can often
be easier & more pleasant to use than a program that can do everything the user might need...if
they take the time to figure out how.
It’s also a sort of warning against trying to plan out a ton of fancy features into a
program at the very beginning, as it’s entirely possible the program’s final form will be
deliberately pruned down to a few essentials anyways.
Part of the programming aesthetic values excellence in a singular domain over slightly awkward
universality.
Take the success of one-trick ponies like MinimaList, a to-do list app that trades heavily
on *not* incorporating a ton of features like its competitors - they’ve built quite a
following among iOS users by doing one very simple thing very well.
In the physical world, tools and objects that try to be highly multipurpose often end up
being practically useless for any of the things they’re designed to do.
I love my Swiss Army Knife, but I can’t think of a time I’ve used it & wouldn’t
have preferred having a knife, a screwdriver, and a pair of scissors instead.
You may have also encountered coworkers who are mired in too many different projects to
make a dent in anything, who just want to put their head down and grind on a single
thing until it’s done, without being called about something else.
They’re good workers, but if they were worse, they might be better.
Another familiar trope in software design is “Self-Documenting Code,” the idea that
well-written programs are easily parsed by anyone reading them, as if the commands and
variables were chosen for the purpose of explaining to a *human* what each step in the algorithm
is doing.
One survey found that almost 80% of developers, when asked what quality makes good code, gave
an answer something like “Readability.”
At first, this might seem counterintuitive - it is called “code” after all.
These are commands intended for computers, not people.
If it’s faster or more efficient to achieve some goal with a couple lines of densely-packed
incomprehensible symbols, so long as it works, who cares if a human can’t understand it
easily?
Well, the ideal of code that’s so simple and clear that both humans and machines can
understand it easily speaks to a sort of universality and clarity of purpose that is generally considered
to be a good sign, indicating that the program is well-thought-out, easily modified, and
not choked with unnecessary complexity.
There’s also an echo of Once and Only Once here - if I have to consult some lengthy document
or block of comments to figure out what a subroutine is doing, the intent and implementation
of that subroutine are being kept in different places, which is awkward and invites problems.
The same sort of principle can be found in the design of objects and systems.
If I invented a pair of scissors that required a five-page instruction manual to know how
to use, regardless of how clever my mechanism was, it would be a total failure compared
to a standard pair of scissors, which convey all the relevant information about how to
use them in their shape.
Fingers don’t fit in little hole, they fit in the big hole, my thumb has to go in here,
oh hey I can cut stuff now.
Designers tend to think of labels and instructions as the absolute bottom rung of user interface
design, a last-ditch effort when all other elegant means of communicating to the user
have failed.
Ideally, a design should speak to the user on an intuitive level, where they want to
do a thing and, without even realizing it, find themselves using the object exactly as
the designer intended.
The object shouldn’t need documentation, it should be its own documentation.
Now, obviously, the aesthetic of programming doesn’t apply to everything.
One can easily imagine a modern-day Pythagoras whining about how unintuitive and clunky the
square root of 2 is, or an authoritarian dictator suggesting that political power should be
concentrated in a single person, because “once and only once” is just more elegant.
There are plenty of places where a well-meaning coder might ruin perfectly good systems in
an effort to make them look more like code and less like...whatever actually works.
But considering how programming culture has been built around effective use of abstraction
& structure, it’s no surprise that there are some useful tidbits in there.
Have you found any of them useful?