Preface to the Fifteen Properties
The program of this serialized essay is to go through the fifteen properties/transformations that Christopher Alexander defined for buildings in The Nature of Order, and try to map them onto software and software development. I do not promise to address them in the sequence they appear in the book, though so far it looks like the book's sequence is fine for now. I also do not expect the properties of software to match up perfectly 1:1 to the properties of buildings, but I am nevertheless proceeding through the properties as given to try to see how well, or even if, they fit. I will address any amendments in a conclusory issue.
This first property, levels of scale, which is also the first one in the book, is fortunately an easy one.
What did Christopher Alexander mean by levels of scale? Literal levels of literal geometric scale. That is, the architecture has prominent features that are big, medium, small, and tiny, and potentially many levels in between. We ask:
- How many discernible levels of scale are detectable? - What is the relationship between the ratios of scale A to scale B, scale B to C, C to D, and so on?
The way you get levels of scale, he argued, is through a recursive process of differentiation, and if you're not at least simulating that, then you're going to get those big, discontinuous jumps in scale that you see in modern architecture. Here are some examples:
The Hagia Sophia has strong levels of scale; 432 Park Avenue does not.
The Alhambra has strong levels of scale; the Seagram building does not.
The Forbidden City has strong levels of scale; the Gherkin does not.
This is not an ancient vs modern buildings thing: The Golden Gate Bridge has pronounced levels of scale, while the Giza pyramids do not.
Levels of scale seem to be prominent in buildings up to and including art deco, but then evaporate by Gropius✱. Early Mies and Le Corbusier works exhibit levels of scale, as does Frank Lloyd Wright (who was two decades older than the rest of them), but much less prominently in their later works. Levels of scale start to show up again in the postmodernists, like Michael Graves and Philip Johnson's later work, but the bleached, neofuturist skeletons and carapaces of Calatrava or Hadid, or the glinting prisms of Piano or Foster, while their gross anatomies are quite striking, are relatively featureless when you zoom in.
✱ I am aware that Gropius's career overlapped considerably with the art deco movement, but trends take a while to diffuse.
There is perhaps hope for a resurgence in levels of scale in parametric architecture, though the strategy here seems largely to be to generate a set of parts which are fabricated for you in a factory, which you then bolt on to the façade of an ordinary Cartesian box. Indeed, a survey of contemporary architecture would suggest it is still hemmed into Venturi/Scott Brown's duck-versus-decorated shed dichotomy: either the building manifests as some kind of sculpture, or it's just a box with some bling on it.
The supertalls are kind of a weird mix of both, though, because so much of the building's volume is devoted to itself, either in load-bearing structure just to keep it standing, or services to deal with the enormous, vertically-stacked square footage (lots of elevators, staircases, electrical, HVAC, and ultra-elaborate plumbing, as every couple dozen floors there needs to be a huge cistern because of the physics of pumping water up a tall building). Every 20 to 30 floors of the Burj Khalifa, for example, there is a dedicated, two-storey mechanical level. Taipei 101 has an infamous tuned mass damper that fills a multi-storey atrium at the top of the building. It has been turned into a tourist attraction.
I suspect a reintroduction of levels of scale—in any radical, structural way—is going to depend on entirely new methods of construction. All it takes is a walk around any city to see that the vast majority of buildings involve the same strategy: a pancake stack of reinforced concrete around a solid core. Newer buildings may involve one or two engineering gimmicks—a cutout or a cantilever somewhere—but they tend not to deviate too far from this basic pattern. Why? Perhaps because contractors understand how to deliver it, and it's easy to calculate the ROI per square foot on a spreadsheet.
If we want to see prominent levels of scale in contemporary architecture, a good place to look is Africa, where they never really quit.
A building is a three-dimensional volume, to be sure, but I submit buildings are volumes with a bias, and that bias is dictated by gravity: so much of the function of a building is to map its three-dimensional volume onto a two-dimensional area of floor space. That is, a building can be understood as a stratified protrusion out of the two-dimensional surface of the building site. And every building site can be understood geometrically (and therefore topologically) as a region on the surface of a sphere—because it literally is a region on the surface of a sphere. This means the building, or rather its site, is going to have neighbours.
This is the connection between levels of scale in buildings and levels of scale in software: The neighbours of a building are, in their most basic way, nodes in a graph projected onto a sphere. Physical connections between them show up as paths and roads. But there are other relationships—social, political, economic—that if they were made visible and superimposed, would crisscross the surface of the planet like a ball of yarn. Levels of scale can be understood as how many of these nodes we can bundle up and treat as a single thing—a single center.
Indeed, Alexander was very concerned with the question of how one creates a building, that in addition to functioning for its own private purpose, also heals its neighbourhood, and how healing the neighbourhood could heal the town, and the region, and the country, and the planet. The overarching structure of A Pattern Language was organized in terms of levels of scale, beginning with the distribution of autonomous territories, decrementing steadily in size until it contemplated trinkets on a shelf.
…but it absolutely does have a topology.
✱ Okay, when I say geometry, I mean “distances and angles matter”, whereas in topology it's connectedness and plasticity that matters. Strictly speaking, software does have a geometry by dint of being a phenomenon embedded in ordinary spacetime, just as it is subject to the ordinary laws of physics. However, the fact that people regularly distinguish “physical” from “digital” implies that the effects of ordinary dynamics are diminished, and the software's own “dynamics” tend to dominate. Likewise, the geometry of ordinary (continuous) Euclidean spacetime tends to take a back seat to the discrete topological “spacetime” of clock ticks and memory.
Running software is a process. The code we write—that generates said process—embodies (almost) the maximum possible amount of detail about it. It mixes together conceptual entities that represent real-world things that ordinary people actually care about, with the minutiae of managing available physical computing resources, as well as the software program itself.
So what? Well, at the very bottom, every piece of code is a mathematical object (called a formal system), which means it can be manipulated mathematically. We know this: the code we write isn't actually the most detailed possible representation—filling in the remaining blanks is what the compiler (or interpreter, but the distinction doesn't matter here) does for us. If a compiler can add detail in one direction, then an analogous process in the other direction can take it away.
Compiled code in general can't be restored perfectly to source, because compilers tend to throw away the very information that makes code intelligible to humans. (There are also programs called packers that obfuscate machine code to make decompilation more difficult.) Decompiling C is a full-time job, and only a few people know how to do it. Java is a little easier, but symbol names are lost. Interpreted languages generally remain untouched, though many interpreters “compile” code to an internal representation on the fly.
Of course we aren't interested in a formal process for taking away detail per se, but rather its hypothetical product. A mathematical object with detail removed is still a mathematical object. The formal system that is software source code maps onto a (directed, and hopefully acyclic) dependency graph. When the code is running, it maps onto a call graph. There is no reason why we can't extend—or rather contract—this idea in the other direction.
Herbert Simon's The Sciences of the Artificial opens with the following statement:
An artifact can be thought of as a meeting point—an “interface” in today's terms—between an “inner” environment, the substance and organization of the artifact itself, and an “outer” environment, the surroundings in which it operates.
This corresponds exactly to Alexander's form and context defined in his PhD dissertation, Notes on the Synthesis of Form. To recap: the context is the part of the world you don't change, and the form is the artifact you make to fit the context. The thesis held that the totality of design concerns—what Alexander called fitness variables—along with their mutual interactions, can be represented as a fitness graph. I further submit that some subset of the points of this graph we can take to be the perimeter, or what Herbert Simon called the interface, between form and context, between inner and outer environments.
The nodes of a fitness graph are the fitness variables: discrete design concerns which are in a binary state of being either satisfied or unsatisfied. The links between the nodes represent mutual interactions between them. Depending on the current states of both nodes on either side of the link, satisfying one fitness variable will also satisfy the other one (if it also starts off unsatisfied) or de-satisfy it (if it was already resolved).
Christopher Alexander's fitness graph was undirected, but an undirected graph is functionally equivalent to a directed graph plus the same directed graph with all the edges flipped around. (Which is also equivalent to just removing the arrows from the edges.)
What we will find, if we designate that perimeter, is that there will be many more perimeters besides. Fitness graphs are sparse; they are what Simon called nearly-decomposable systems. That is, the nodes on the perimeter will connect to another subset of nodes, which in turn do not connect to the original perimeter, thus creating another, internal perimeter. The process of adding detail to the fitness graph by adding nodes and connecting them to their neighbours will naturally nucleate into recursive clusters, each with a set of points that serves as the interface between outer and inner clusters. That is, the concern represented by each point will have a definite “distance” from the “outside”, with sufficiently “distant” nodes representing details upon details upon details that are only of concern to those who have to implement them.
Of course, a building will begin with this structure too, but it will eventually map onto the geometry of a physical construction site, which sharply constrains the space of possibilities. In software, we have many more degrees of freedom, which means many of our constraints need to be artificial as well.
The fitness graph is, unfortunately, not a complete picture. It can only model what the misfits are, not how to respond to them.
Every computer system—indeed every process model, whether it involves computers or not—can be understood as being composed of two kinds of subprocess:
- procedures that terminate, - infinite loops, such as event loops, that nominally run forever (although will ultimately also terminate one way or another).
A terminating procedure that is subject to additional guarantees—namely a lack of side effects—can be said to be equivalent to a (computable) mathematical function. Even procedures with side effects can be modeled as functions, if the side effects can all be accounted for. This is exactly how the language Haskell operates: you model the side-effect-generating procedure as a side-effect-free function, and then you pass the entire universe✱ into the function and get a new, updated universe back out.
✱ Or at least a big enough chunk of the universe to account for the total extent of the state that has been changed. This is why the Haskell people are all about monads: smoothing out pesky wrinkles in a process that get caused by the myriad details of reality is essentially what monads are for.
We can therefore model any process as a function (or more generically morphism, but the distinction isn't really important here), of the form:
f : S0 → St
…where f maps the initial state S0 to the terminal state St. The concept of “state” can be as big as you need it to be to encapsulate all the changes—or rather ways the system can change—you are interested in modeling. Dragging this back to reality, the expression above is equivalent to saying something like:
- Alice is currently in state S0 - Alice has goal St - Alice waves magic wand f - Alice is now in state St.
This elision of detail about how Alice gets from S0 to St can be understood as the most zoomed-out scale of describing f. The reason why I'm going through the trouble of introducing this notation is that structure-preserving transformations (functions, morphisms, whatever) compose, like this:
This diagram is saying that there is some transformation f0 that takes the state S0 to state St-i, and another transformation fi that takes St-i to St, meaning that f is the composition of f0 and fi, written f = fi ∘ f0.
So we can imagine that in between S0 and St there is some intermediate state St-i, and while the magic-wand transformation f may not be known in detail, there is a known transformation fi which will take St-i to St. That leaves the details of transformation f0 to work out.
Or, alternatively, you could say that f0 is known and fi is not. The point is that any transformation can be composed from arbitrarily many sub-transformations, and that levels of scale in the implementation of a process can be construed as these recursive compositions of smaller transformations. Conversely, any transformation not detailed enough to be executable directly by computer can be split recursively until it is. You will also notice that there will be certain fis that look the same as others. These can be coalesced together and referenced from multiple places (what gives us our dependency graph).
Some subset of the states Sn will correspond to elements of the fitness graph defined above. No doubt the process of adding detail to f will yield more states that were not previously identified. Finally, the composition structure fi ∘ fi-1 … ∘ f0 can also be represented as—you guessed it—a directed graph.
This structure is also amenable to analysis by handy tools such as Markov chains, Petri nets, etc.
This, I propose, is how we get at levels of scale in software systems: viable views of the system, starting with its entirety from the “outside” in, at increasing levels of detail. There are invariably more details at smaller scales than at larger ones; a greater number of “inner environment” concerns—those of engineering and/or implementation. And again, this model need not be relegated to software, but any process that aspires to be well-defined.
In my own work, I have endeavoured to address levels of scale with something I call a specificity gradient, which should not be confused with gradients, another one of the fifteen properties. I should note though that gradients interact with levels of scale insofar as the levels of scale should roughly follow a gradient instead of big discontinuous jumps.
Normally when we talk about “scale” as it relates to software, we mean scalability, which almost always means doing huge numbers of operations in parallel. I submit that this typically entails multiple identical copies of the same configuration doing the exact same thing at the same individual scale. This is manifestly not the same thing we are talking about. Where levels of scale manifests in the actual scaling of e.g. a computational service, to the extent that it shows up at all, is in the architecture: all the orchestration, observability, and monitoring infrastructure that wouldn't otherwise need to be present.
There is a dirt-common aspect of software development where we can use most, if not all of the original fifteen geometric properties with little if any modification. We can do the same with the eleven properties of colour.
There are entire classes of computational problems that are useful to reason about geometrically, for some value of the term. We don't encounter those nearly as often as this though.
The overwhelming majority of our concerns around levels of scale in graphics will be raster and vector canvases for a 2D screen. Three-dimensional graphics, whether on a screen, VR, or AR, generally occur in simulated (or in the case of AR, overlaid) space, so other than the missing physics of real building materials (the significance of which can be a different discussion), it's a straight port over.
Any ordinary screen, though, we can treat as a canvas, albeit one that (usually) emits light rather than reflecting it. Here, the geometric property levels of scale corresponds to the colour property hierarchy of colors [sic, because I'm writing the properties verbatim]. The general rule for this property, without getting too much into the detail, is that the three most prominent colours occupying the space ought to respect a ratio of areas of roughly 15:5:1. Adjust as necessary for more colours. As with all things Alexandrian, this is not an exact prescription, but an observation distilled from a number of examples. There is three times as much area assigned to the most prominent colour as the second, and five times as much of the second as the third.
Graphical applications have a tendency to split the screen into a work area and a control area. Given these guidelines, that's 70% and ~23% of the pixels, respectively. The remaining ~7% can serve as boundaries and hairlines.
I'm making it a point to include in each of these chapters a section on deep feeling, because it was so central to Christopher Alexander's thesis. So the question is: what does levels of scale, or its absence, feel like?
In a piece I wrote a few years ago, I posited that the fifteen properties from The Nature of Order could be clustered into three information-theoretic categories: conveying information, compressing information, and throttling throughput. Under this regime, levels of scale is a compressing property because it induces an order that makes information systems more understandable.
Though now that I'm thinking about it, levels of scale also act as a throttling, or rather, shaping or ordering property. Consider how, in the dial-up days, we would use progressive JPEGs on websites to ensure that the visitor would see something fill the space immediately as the bits trickled in, even if it was chunky and blurry.
The point—at least in my interpretation—of levels of scale, is that the artifact in question is intelligible—distinguishable, comprehensible—from afar, from low levels of detail, but more content is revealed as you approach it. When buildings lack levels of scale, they tend to be like a beehive—bulk containers of undifferentiated activity, that don't have anything else to tell you.
What is the failure mode of a lack of levels of scale? I submit it's having an ocean of objects (centers) all at the same scale. Differences among the parts and pieces get washed out by relative similarities, which makes them hard to keep track of. Depending on the context, this could be either boredom- or anxiety-inducing.
When there is a definite membrane around the system, the outermost scale has an effect of obscuring its contents. While a Mies skyscraper may follow an exacting geometrical formula, it is ostensibly intended to appreciated as a monolith: what goes on inside is the business of its tenants, and none of yours. Maybe stop asking so many nosy questions. Maybe don't think about it too hard.
When the perimeter of the system is less pronounced, such as is often the case with software, it can seem hopeless, like it goes on forever—a sea of sleepy subroutines, all alike. These are real feelings, and they can be ameliorated by strengthening and differentiating the gross anatomy of the system.
That's really what it's about: creating centers. Centers are things; centers are places. We can identify with them. We can have favourites. But we need to be able to pick them out in order to do that. Levels of scale is the first of fifteen properties and their concomitant structure-preserving transformations that are focused on creating such centers. These transformations themselves need to be transformed in order to be applied to a different medium.
The feeling of levels of scale is not only a sense of comprehension, but also a sense of situation within a context. The feeling of it missing is alienation, monotony, and/or overwhelm. We can point to just about any piece of software as an anti-example of levels of scale, but what would software look like that was especially organized this way? That connected to, and healed its environment? That was intelligible at every scale? That, as Alexander said, was morally profound?