Why do the fifteen properties, and the feeling of life that accompanies them, show up so rarely in modern places and things? And why is software, the most modern of all media, the one venue where the fifteen properties do regularly appear?
Here is my guess: the fifteen properties arise in situations of extreme economy, where the design is constrained by the need to extract as much value as possible from some precious resource (e.g. materials or labor). In the modern developed world, these resources are abundant. In fact, they are so hyperabundant, relative to the practical demands placed on our buildings and artifacts, that we can afford to waste them. The bureaucratic and technocratic systems that create the built environment today are, accordingly, ludicrously inefficient.
Note that there seems to be a paradox here: the modern economy is highly efficient at distributing resources. But it is not efficient at using resources. This isn’t actually a paradox, though; it’s exactly what you should expect in an environment of hyperabundance. The challenge, in such an environment, is not figuring out how to use resources efficiently, but figuring out how to use them at all.
Imagine a startup that receives an influx of investment. Previously, they were operating on a shoestring, but now they have boatloads of cash. Their constraint shifts; it’s no longer “how can we stretch our money as far as possible,” but “how can we hire fast enough and scale up fast enough to return a profit to our investors?”
The twentieth-century economy, broadly speaking, is like this startup. A massive influx of resources (in the form of cheap fossil fuel energy), coupled with a population explosion, created an environment where success and power flowed to those who could spend resources the fastest. I’d bet that this can’t, and won’t, go on forever. But at least for now, it’s the situation we’re in.
Christopher Alexander was a harsh critic of the architecture that emerged from this 20th-century milieu. But his own critics are quick to point out that the examples he gives of good architecture (i.e. living structure) tend to be old. They see living structure as a relic of a bygone era, and dismiss Alexander as hopelessly nostalgic. But the thing that stands out to me about Alexander’s examples is not their age, but their efficiency. One of the characteristics of the living structures that Alexander analyses is that their elements seem to resolve many forces simultaneously. Each center in the design is doing multiple things.1
Here is a simple example of a living building process: a farmer in England clears the stones from their field, and builds a wall with them, to keep their sheep in. They don’t throw the field-stones away and then buy wall-building materials from somewhere else. They work with what’s on site. The building process is a simple matter of reshaping the material that is already present: moving stones from a place where they are harming the system to a place where they can help it.
Contrast this straightforward process with the way construction typically works in today’s globalized economy. Resource extraction, design, and construction are separate and abstracted from each other. Materials and fuel might travel halfway around the globe before arriving at a construction site. Huge projects are funded by investors who have never even visited the area where the construction is to take place. And when modern buildings are torn down (as they inevitably are, mere decades after being built) their materials go to landfill. These processes generate enormous wealth. But they are also enormously inefficient in their use of materials and labor. They only make sense in an environment of hyperabundance.
Why has the hyperabundance of the modern economy affected the software industry less than the construction industry? Why do ideas like cross-functional teams, continuous improvement, feedback loops, and craft remain relevant to us? I think there are a few reasons. But first, I think it’s worth pointing out that computing resources (CPU, memory, disk space, network bandwidth) are hyperabundant, and we are, as you might expect, wasting them profligately. Various commentators have criticized the software industry for this waste. Casey Muratori, for one, loves to rag on programmers for wasting CPU cycles.2 He’s not wrong (about the waste) but what he doesn’t acknowledge is that CPU time usually isn’t the limiting factor on software’s success. In our current economic environment, wealth will generally accrue to those who can waste more CPU than their competitors.
So, what are the inputs to software development that aren’t hyperabundant? In other words, what are the constraints we’re optimizing for when we do things that create the fifteen properties?
In my experience, the constraints tend to be:
How quickly a programmer can figure out how the software works and how to change it
How many programmers you can hire
How efficiently you can distribute work among those programmers.
These constraints come, respectively, from three more fundamental ones:
The working memory and processing ability of a human brain
The supply of programmers in the world
Amdahl’s Law, which says that as you parallelize a task among more and more workers, the total time taken approaches the time required for coordination.
These constraints aren’t likely to go away anytime soon.
I believe that Alexander’s fifteen properties are relevant for software developers because they allow us to operate efficiently within these constraints. They help us conserve our cognitive resources, and they allow multiple teams to work on the software in parallel. Exactly why and how they work is a bit of a mystery, though. That’s the mystery I’m trying to solve in this series of posts.
9. Contrast
In a poorly-structured codebase, all the code has a similar texture. Everywhere you look, it’s approximately the same: a mishmash of different stuff. A bit of SQL, a bit of calculation, a sprinkling of HTML. Every function seems to operate on a mixture of domain concepts and language-level primitives.
When concerns are separated, on the other hand, there is contrast between the parts. The UI code looks very different from the database access code. When you open a file, you can tell at a glance what type of thing it is, and know where it fits in the architecture.
Sandi Metz has a technique she calls the squint test: you lean back and squint at the code, looking for changes in shape and changes in color. The more coherence and consistency you see in each part, the better the code is.
For functional and cognitive clarity, contrast is [...] practically necessary: the shop in the neighborhood is different from the houses next to it. [... Contrast] allows each center to take its proper nature. It permits more intensive attention to individual functions. And it creates a feeling of distinction which relaxes people, because it acknowledges and permits different dimensions of experience.
Contrast is the thing which creates differentiation, and allows differentiation. It is the differentiation of the void which gives birth to matter. All differentiation requires that contrast is created in space, in order to give birth to anything at all.
—The Phenomenon of Life, p. 203
Increasing contrast, whether in code or in the built environment, is ultimately a matter of reducing entropy. Consider the contrast between the green pastures and the stone walls in the photograph above. This contrast was created by a gradual process of entropy reduction: farmers moved scattered stones out of the way and piled them up into walls.
There is something very simple and natural about these ancient stone walls, and indeed we tend to think of the landscape they create as part of nature. But as Christopher Alexander points out, this landscape is not “natural” in the sense of being wild and undisturbed, because of course all of it was made by people. The whole of southern England is one continuous manmade structure covering thousands of square miles, which was built, gradually, over thousands of years. Every part of it is adapted to human needs.
It is remarkable that the contrast between walls and pastures enhances, rather than detracts from, our feeling of naturalness, because we can easily imagine many other contrasting structures that would have the opposite effect — e.g. a glass-and-concrete office building. Contrast, of all the fifteen properties, is perhaps the one we have to be most careful with, because it can hurt as easily as it can help. The trick to creating contrast is to do it in a way that has the same natural grace as the walls and roads and fields and forests of the English countryside. You have to be “more natural than nature itself,” to borrow a phrase from Alan Watts. The way to do this, I think, is simply to avoid grandiose ambitions. You want to reduce entropy incrementally, and only as far as it helps. Remember that the overall goal is to improve efficiency, so you should increase contrast only if the effort it will save in the future is worth the effort you put in now. It is this global efficiency, I think, that creates the feeling of life in the whole.
Contrast applies to team structure as well as code. At Pivotal Labs, each project was undertaken by what we called a balanced team — a cross-functional group of people that consisted (usually) of a product manager, a designer, and several engineers. The division of responsibilities among these roles was clear and crisp:
PMs were responsible for balancing stakeholder needs and prioritizing work.
Designers were responsible for UI and UX.
Engineers were responsible for the internal structure of the software, and for providing relative cost estimates for programming work.
Anyone could weigh in on someone else’s area of responsibility, but the responsible party always had the final say. This clear contrast between the roles meant that a team could generally negotiate its way to a plan fairly quickly and painlessly — perhaps with some grumbling, but no lasting resentment — because we all knew the rules by which we’d agreed to play.
10. Gradients
Adaptation is a recurring theme throughout this series. We feel comfortable, and we feel that our surroundings are natural, when centers are adapted to their context.
The forces that shape centers vary continuously throughout space. As a result, when a structure is made of many similar centers, the centers will generally not be exactly the same. Each one will be slightly different as it adapts to the unique combination of forces in its particular location. The result will be a gradient of shapes, which reflects the gradient of forces in the environment.
When you look at the methods of a class or the functions in a module, you often see a gradient from public/primary to private/secondary. Similarly, when you read the tests for a module, you see a gradient from error cases to edge cases to central cases. These gradients exist because of another gradient: human attention, as a function of the position of the scrollbar. We tend to start reading at the top of the file and scan downward. If we can't find what we're looking for, our attention is likely to drift. Good code acknowledges this by putting the stuff people look for at the top.
Gradients will follow as the natural response to any changing circumstance in space, as centers become adapted correctly to the changes which move across space.
—The Phenomenon of Life p. 206
Gradients of activity occur over the life of a software project. At the beginning of a project, much of the work is user research, UX design, and planning. As development ramps up, design gradually ramps down. Eventually, the project becomes less exploratory, and settles down into a rhythm of feature development. Finally, as the software product matures, the pace of development cools further, and the codebase stabilizes. These gradients form naturally when we respond to the forces on the project in the simplest way possible: by doing the most valuable thing at every moment.
11. Roughness
Every living system has a certain looseness of form, a relaxed and casual roughness. This roughness comes about not because the system is sloppily made, but because it is precisely adapted to the complex system of forces in its environment. By contrast, rigid, geometrically perfect forms tend to feel dead and sterile, because they are not adapted to the real forces around them. Their shape is imposed from outside, based on artificial images of how things “should” be, and not on reality.
Roughness is everywhere in software systems. It is perhaps the second most fundamental property of good software, after levels of scale.
For example, roughness occurs at the semantic level when we choose an “incorrect” solution for its performance or simplicity. As Linus Torvalds pointed out,
“pi = 3.14” is (a) infinitely faster than the “correct” answer and (b) the difference between the “correct” and the “wrong” answer is meaningless.
Approximations and heuristics are often perfectly acceptable, and can be preferable to “correct” solutions because they are cheaper either in computing resources or programmer time.
Roughness often involves relaxing artificial rules and constraints to get a globally better result. I love test-driven development and algebraic types, but there are times when it’s just too hard to write precise tests or types for something, so sometimes I let things be a little unsafe to avoid contorting the code.
Roughness occurs at a syntactic level too: it’s often better to relax line-length constraints than to format similar chunks of code inconsistently. Some code formatting tools (I’m looking at you, Prettier) are not able to take context into account when deciding whether and where to break lines, which leads to awkwardnesses like this:
const users = [
{
userId: 1,
username: "Alfie Carmelita",
},
{ userId: 2, username: "Gina Roshan" },
{ userId: 3, username: "Shug Nabu" },
{
userId: 4,
username: "Rahman Fraser",
},
{ userId: 5, username: "Toshe Lyuben" },
{
userId: 6,
username: "Sergio Nilofar",
},
];
(source: Anthony Fu, https://antfu.me/posts/why-not-prettier)
This example would almost certainly be more readable if each of the user records were on one line:
const users = [
{ userId: 1, username: "Alfie Carmelita" },
{ userId: 2, username: "Gina Roshan" },
{ userId: 3, username: "Shug Nabu" },
{ userId: 4, username: "Rahman Fraser" },
{ userId: 5, username: "Toshe Lyuben" },
{ userId: 6, username: "Sergio Nilofar" },
];
Locally-consistent, symmetry-enhancing formatting matters more for readability than the global consistency of line length. Yet Prettier enforces the latter at the expense of the former, because that's easier.
Note that this example is at odds with our everyday sense of “roughness.” The rigid yet inconsistent formatting enforced by Prettier looks “rough” to us, while the example I’ve called “rough” looks regular. But there is no contradiction. In fact, this is the whole point of Alexander’s concept of roughness. Something that seems rough to a machine, because it defies the simplistic rules by which that machine operates, can feel simple and natural to us. Roughness arises in its purest form when every center is shaped only by the forces that really matter.
The psychological effect of this subtle kind of roughness is that one perceives the program as down-to-earth, humble, handmade, human-scaled. Roughness in an object touches the heart, because it shows that the maker was free — free to do the work in the most aware and effective way, constrained only by what really mattered in that situation.
In our time, many of us have been taught to strive for an insane perfection that means nothing. To get wholeness, you must try instead to strive for this kind of perfection, where things that don’t matter are left rough and unimportant, and the things that really matter are given deep attention. This is a perfection that seems imperfect. But it is a far deeper thing.
—Christopher Alexander
This reminds me of a proverb about the game of Go, which says that every move you make should be doing two (or more) things at once. It also reminds me of Kent Beck’s principle of mutual benefit, from Extreme Programming Explained.
Even though Casey criticizes “clean code,” it’s worth noting that his code (exemplified in the linked video) has the Alexandrian properties, including levels of scale and symmetry, and that his overall development practice is deeply adaptive, incremental, and empirical. The 15 properties are not just about clean code or readability — they are about efficiency in the broadest sense.