FWIW, I am a huge fan of Christopher Alexander’s work and own a copy of The Nature of Order.
Chris’s pattern language idea certainly took strong root in software engineering, but his fifteen properties of quality (which I personally think are a far more interesting idea) are very tied to physical space, which makes them more difficult to use in a programming context. However I’ve given it my best shot:
1) Levels of Scale
At first glance this one is very spatial, but I think it has programming merit. This excerpt could be taken as describing the differences in scale (depth of abstraction) between modules - a low level one, a medium level one, a high level one, and so on:
To have good levels of scale, it is extremely important that the jumps between different scales of centers not be too great or too small.
2) Strong Centers
If a “center” is taken to be the design of an object or module, I think this one translates from architecture to programming rather well. Think of modules/objects while reading this excerpt:
A true center is defined not only by its internal cohesion, but by its relation to context. A strong center can only occur when other centers are intensifying it. Like levels of scale, the concept of strong centers is recursive. In something which is alive, a strong center is made of many other strong centers, at different levels, which in turn make us aware of the whole they compose.
Boundaries is extremely applicable to programming. I would consider this the API surface of a module/object, plus how well it manages to keep its internal state encapsulated.
The articulation of a form depends to a great degree on how its surfaces are defined and meet at edges.
4) Alternating Repetition
At first glance, this one is very spatially-oriented. It could perhaps be stretched to mean that modules should be internally similar – functions should take their parameters in the same order and so on.
Elements need not be perfectly identical to be grouped in a repetitive fashion; they must merely share a common trait of size, shape, or detail characteristics allowing each element to be individually unique, yet belong to the same family.
5) Positive Space
Another spatial quality, this could be stretched to mean something like ‘synergy’ among modules – what will consume your object, and how well does that interaction work? Is the abstraction seamless?
Where an element occurs in space, the element not only exists with its own shape, but it also acts to define the shape of the space around it. For something to be whole, both the element itself and the space around it must engage one another, each intensifying the other.
6) Good Shape
At first I thought this was very ambiguous (what is “good”?), but the excerpt below describes how a good object is composed of other, simpler objects.
Good shape happens when the surfaces and edges of a form have strong centers in every part of themselves. A good shape, even if complex, can usually be broken down easily into more simple shapes. A good shape tends to contain a high degree of internal symmetries, an overall bilateral symmetry, and a well-marked center.
7) Local Symmetries
Sort of a repeat of #4 Alternating Repetition, this one seems to describe symmetries on a smaller scale, or of a different sort. Perhaps within a small part of the source code?
Overall symmetry in an object tends to look mechanical and lifeless, usually due to the fact that local symmetries are absent within the overall form. However, when there are local symmetries, centers tend to form and strengthen the whole.
8) Deep Interlock
Normally “intertwingling” is a bad thing in programming. We’re taught to prefer cohesion over coupling, and I don’t really want my source code to look like a Persian rug. Not sure what to make of this one. Perhaps this could refer to a deeply pervasive abstraction, such as “everything is a file” or “programs pipe text to each other”?
Forms which have a high degree of life tend to contain some type of interlock – a “hooking into” their surroundings – or an ambiguity between element and context, either case creating a zone belonging to both the form and to its surroundings, making it difficult to disentangle the two.
Another visual one. I think this is related to boundaries, but it also makes me think of Alternate Hard and Soft Layers.
Works of art which have great life often have intense contrast within: rough/smooth, solid/void, loud/silent, empty/full. It is the difference between opposites which gives birth to something. Contrast is what often gives other principles their degree of life – the intensity of the boundary, the markedness of the alternating repetition.
10) Graded Variation
This makes me think of the gradient that arises while using the Model-View-ViewModel pattern. The View describes what you see, the Model encapsulates the business logic, and the ViewModel exposes the data from the Model, in a form that the View can consume.
In something which has life, throughout the whole there are graded fields of variation, often moving from the center to the boundary or vice-versa. We are able to read the character of a larger center often because of the gradation of smaller centers across the larger form.
Crufty code is often crufty because of years of accumulated bugfixes, not because it started that way.
Roughness is the odd shape, the quick brush stroke, the irregular column size or spacing, the change in pattern at the corner – it is adjusting to conditions as they present themselves with meaning, but without ego or contrived deliberation.
Though it may look superficially flawed, especially with human perception accustomed to mass-produced regularity and perfection as a goal, an object with roughness is often more precise because it comes about from paying attention to what matters most, and letting go of what matters less.
A program design which is thoroughly self-similar seems a good thing to me. I again come to think of the Unix philosophy: everything is a file, programs pipe text to each other…
When echoes are present within a design, all the various smaller elements and centers, from which the larger centers are made, have a certain sameness of character. There are deep internal similarities, or echoes of one another, which tie all the elements and centers together at various scales to form a cohesive unity of being.
13) The Void
Here’s another puzzlingly spatial quality. I’m not quite sure how to characterize a lack of code.
It is the pause which allows us to interlock with a piece of music and feel its depth. The presence of void, at many scales, provides a contrasting calm to alleviate the buzz and strengthen the center.
14) Inner Calm
This one makes me think of OpenBSD (I know my fellow lobsters are also fans).
Living things tend to have a special simplicity, an economy developed over time in which all things unnecessary, or not supporting the whole, are removed. This does not preclude ornament, as even in nature ornament has its very necessary place. What simplicity does is cut away the meaningless attachments to an element, the things which often distract and confuse its true nature. When this is done, an object is in a state of inner calm.
Hard to distinguish this property from the other fourteen, but I guess it’s intended to draw them all together.
Not-separateness is the degree of connectedness an element has with all that is around it. A thing which has this quality feels completely at peace, because it is so deeply interconnected with its world. There is no abruptness, no sharpness, but often an incomplete edge which softens the hard boundary. The element is drawn into its setting, and the element draws its setting into itself.
What do you all think?
One additional bit that’s usually not discussed in the software-engineering version is that in architecture, the pattern idea, especially as presented in the Alexander/Ishikawa/Silverstein book, had a strong slant towards democratization and empowering the layperson. Their idea was that instead of architecture being a professional design problem, where only trained architects can come up with solutions, systematizing the space of design variation in an accessible pattern language would enable regular people to take over much of the design themselves. They hoped this would humanize architecture by bringing it closer to people and communities, replacing the overarching role of The Architect with a bigger role for laypeople, who could use their more on-the-ground, situated knowledge to adapt architecture to their locations and needs.
In computing, that’s not really at all how design patterns have ended up used. Arguably almost 100% the opposite, especially in the form they take in places like Enterprise Java: the PatternFactoryMethodGenerator version of software patterns is more like the top-down, mega-scale, modernist architecture that Alexander et al. were hoping design patterns would help build an alternative to.
Which maybe is fine, if the idea doesn’t translate well, but is an interesting difference. The original goal reminds me more of the goals of people like Ted Nelson or perhaps Richard Stallman, that computing should be rearranged in a way such that ordinary users can control their own computing, instead of outsourcing design to professionals. But it’s not clear that software patterns in the sense they’re used in software engineering are really a path to that; it would have to be a pretty different kind of pattern.
13) The Void - makes me think of curried functions in Haskell and Shen and other FP langs. You don’t have to build separate functions and extra names to do the same work, you just assign a new var to a partial of another function and let the natural definition of “function” do the rest of the work.
@ChadSki - since you are the resident expert on Alexander’s extremely abstract writings, I’d like to hear how you think these apply to functional programming. You offer hear FP people say that OO design patterns are easily replaced with “just functions” but clearly there are best practices and not-so-good practices when it comes to how you write those functions.
Sorry, but frankly but it reads like a lot of malarky. To me those words, when I try to figure out what they mean, mean everything. Which, of course, means they mean nothing. The same principle as that of a fortune teller who does not really read your future, but tells you what you want to hear of your future.
I think Alexander is just working with some very abstract and philosophical concepts, which makes the material very difficult to analyze literally.
I don’t think any of the words “mean everything.” Which words specifically were you having trouble with?
I read the nice summary by @ChadSki and none of those quoted paragraphs actually say anything. They don’t convey any information I can go home and study and put into practice.
I felt exactly the opposite. Let’s take the “Strong Centers” quote for example.
A true center is defined not only by its internal cohesion, but by its relation to context.
It looks like you do a lot of Racket and Python. Say we want to create a SQL database library for Racket, how do we decide what code to write first? How do we decide what the most important part of our package is, the “true center”? According to Alexander, the true center is defined by its “internal cohesion” and its “relation to context.” So we should first define what what the internal cohesion would be, probably something like “SQL databases,” and then we should define the context, let’s say it’s “other Racket programs.” This second definition is rather vague so let’s refine, let’s say that the context is “other Racket programs that embrace functional programming and want to represent database connections and transactions as just functions.” This is much more clear, and we can see that the implementation of our library is already becoming obvious: we want to write it in such a way that, when you want to connect to a database, you just write a function like (connect db-host db-user db-password) and when you want to add a value to the database you just do (db-add new-value) or whatever.
(connect db-host db-user db-password)
If you take a look at the SQL libraries in Clojure, they are all over the map. Some represent SQL as files, some as data structures, and some as macros. All of these change not only the “internal cohesion” of the libraries, but also the “relation to context,” that is, how you end up using the library as an application developer, and thus how your application is internally coherent.
So, when working with these abstractions that Alexander provides, we have to really critically apply the abstractions and define the terms for ourselves. That’s why I asked you what words you were having trouble with, and maybe we could tease out some useful, concrete definitions that were more useful to you.
Hi @bsima, I like your approach. But this is all your thinking and you have done it without Alexander.
No, this is an example of applying Alexander’s concepts to programming.
I appreciate you showing me how you think through design tasks! Best