Environments and inhabitants

In one sense, it is simpler for patterns to be recognised in the real world, as the builders and the new owners of the buildings live in the same reality. They breathe the same air and touch the same ground. The new owners lean against the same walls and pass through the same doorway the tradespeople used when constructing the building. The patterns of physical construction make more sense than those of software, as the same values apply to forming and form. We evaluate the construction environment with the same rules of thumb as we assess our final buildings. This is a key difference and relates to a point that Christopher Alexander would rail against.

Christopher Alexander appeared to believe that you cannot design a building on paper. Eventually, you will always need to do the final designing on-site. There is no substitute for being there. However, when we construct software, we don’t assemble a thing in a place, and often, we don’t resemble the future inhabitants.

With software, we rarely construct into a pre-existing situation. Physical construction builds into the world, with all its rules and regulations and the fashions and expectations of the users. There are comparable examples when you write applications, such as developing for a domain with a dominant competitor. In that case, you have to assess the existing users’ expectations and learn the metrics they will use to judge your new application. But notice that we can only sometimes use our judgement to determine what would satisfy the users of our software. That’s why we have to resort to A/B testing. And the new occupants may have very different values from us if we are unfamiliar with the application.

Builders and end users of physical construction share quality metrics because most of them are human. For software, what makes an application’s user comfortable is not biological but often idiomatic or habitual for that user; thus, it is much less likely to be in common with the developer, whose habits revolve around developing and testing their corner of the software.

Then there’s the construction site. If we compare the two variants, we see a difference. The final inhabitants of the physical product live with the same thing handled during construction. But this is not so in software development. Not so much because end users don’t live within the running software, for that is untrue. They do. They have a mental model of what is going on, and they inhabit the space of the application. No, what is different is that the software engineers don’t work in that space. The construction site is unrelated to the application. The end users don’t inhabit the code. The software engineers don’t inhabit the application (except when testing it). With a physical building, both inhabit the same product.

A split like this lends itself to malpractice because the product won’t show signs of dirty work. The developer’s world can be as messy as they like as no apparent ugliness crosses the divide into the application’s presentation. If a builder were to have tangled spaghetti of wiring and pipes along the house’s ceiling, the new owner would be able to see it and would complain about the potential hazard. With software, you can’t see the dangerous wiring. That’s what I mean when I say there are two distinct environments—one world in which the product lives and the other in which the product is designed, constructed, and produced. So, software engineering is closer to the process of designing a production line that produces goods than it is to architecture1.

But even factories have standards, right? Well, they do now, yes. But these standards came about because people uncovered potential hazards in their products. Production lines used to cut corners for the same reasons why code is messy now. There was no pressure to work cleaner or safer; often, it was better to reduce costs. Cotton mills and other factories of the industrial revolution were notoriously dangerous places, often producing dangerous goods and byproducts as well.

Now, in software engineering, at least in those places where we write software to meet strict quality requirements, we see standards and processes coming in to ensure the code factory is sufficiently capable of making the product well enough for human consumption. Code safety audits don’t inspect the code; they review the process by which we write it. Inspecting the code would be like checking every chicken for contamination rather than just checking whether the floors are clean, whether there is a rota, and whether the equipment for keeping everything hygienic is present and in good order.

The separation of environments means the environment of code is different from the environment of the product. This separation partly explains why the GoF book[GoF94] lacks UI or UX patterns. Why would there be? It is a book on patterns of the programmer’s environment, not that of the user.

But what does this mean for software design patterns? Architectural patterns are guidelines for solving repeating problems in the physical environment. Does this mean patterns apply to the software engineering environment alone, the user environment alone, or both, or neither?

The answer, I believe, is both. And occasionally, there is a crossover between the domains. Every problem is a problem of unresolved forces in a context. Every environment will recreate the conditions for certain problems over and over again. Every environment will have some naturally occurring wholesome solutions and some attractive anti-patterns. It doesn’t matter whether the environment is that of an application’s user or the code’s author. Every environment where the contents can change and introduce new interactions and usage patterns can exhibit fertile ground for the emergence of patterns.

However, the split environment complicates things. Resolving forces allows you to create harmony in one domain, but if your actions also affect another, you may introduce new unresolved tensions there without being aware of them—and potentially without any way to resolve them without undoing what you have just achieved in the first domain. It’s like a two-sided maze puzzle where every move must simultaneously be valid for both sides.

Unix programs had good user experience due to this domain split theory. You might think it a bizarre assertion, as command line interfaces aren’t renowned for their usability. But I use the word ‘had’ carefully. Historically, they had better UX because they better fit their users and, thus, their environment. The builders and the end users shared tools and ways of working, thus sharing many values on what made a good program. Programmers and scripters inhabited the same domain as the end users. They had common expectations and mental models of how things worked. The tools, programs, and work products all shared the same environment, which could be why the tools worked so well together. Unix wasn’t just a philosophy but also a combination of using the small tools you make in conjunction with others and the collaboration and sharing model, which appeared around this time.

1

This explains why many programmers like playing games like Factorio.