Design by construction Lassi Kortela 14 Aug 2020 09:59 UTC

Here's a meta email in an attempt to understand the background for our
recurring differences of opinion re: SRFI 198.

The philosophy I follow is what I call "design by construction".

Our API enables users to make an object that has a particular structure,
by virtue of the way the object is constructed. Once we give people a
structure into which they can put stuff, it's out of our hands; we can't
really control what they put in there.

A carpenter can make a shoe rack but can't really stop people from
piling magazines into it instead. He can cover the shelves with a gritty
surface material that makes it convenient for shoes and inconvenient for
magazines. But adding features for the sole purpose of stopping magazine
storage will likely backfire and make life harder for the people storing
shoes. And determined people can still store magazines in a pinch.

The key insight behind design by construction is, instead of defining
rules for proper use and misuse, we should deliberately try to design
objects whose _structure_ guides people toward proper use and is
difficult to misuse to begin with.

Misuse can normally only be prevented to a limited extent. At that
point, we have to say that we did what we can and it's out of our hands.
Trying to prevent misuse by adding rules on top of the basic structure
makes the result harder to understand for people who are well-behaved,
while still letting people get away with many other kinds of misuse.

A simple structure is simple to know completely and to grasp mentally,
behaves in a consistent manner. Empty hash-tables or the empty product
(https://en.wikipedia.org/wiki/Empty_product) behaving consistently re:
other hash-tables and products is a good example. Using building blocks
that are simple and consistent by construction gives much of the joy in
programming. Rule-filled inconsistent systems are unlikely to satisfy
either their users or their inventors very much over the long term.

Now, how does all of the above tie into abstraction? The (visible)
structure of an abstract object is determined by its accessors. So we
follow the exact same design principles as with concrete objects: we
pick something that we think covers all use cases and that guides people
toward good behavior by making it easier to use properly than badly.

Abstraction gives us additional leverage for good design since we can
block parts of the inner structure that we don't like, and expose an
outer structure that is a better fit for the problem at hand. GC hides
pointers so users can't mess with them, which enables the compiler to
make more assumptions about those pointers.

That's why I like an abstract interface in a SRFI. We do well to admit
that it's always a bit pretentious to design something that strangers
will use for decades. We can't do a perfect job; the next best thing is
to is design a simple structure. Beyond that, we can give any amount of
advice; but we know what adages say about advice-giving.