Construction speed and design speed

The final product of the physical building process is a constructed artefact. We develop a structure guided by a plan and continue to use it in the same space and form once the project is complete. The software construction process is vastly different. In software, we routinely construct to verify even small design ideas.

In software, we compile the final product according to our current design, test it, and then go back to designing. We have an intensely rapid design, construction, inspection, and reaction cycle. Those in physical engineering must be positively envious of this because it enables us to construct things to a much tighter spec than they ever could or perhaps should.

If we worked like this in physical architecture, it might look like the following.

  1. We have a design for a bridge, so we want to test it.
  2. We launch a fleet of drones to build it, and they complete the work in under an hour.
  3. Then, we take a robot truck and drive it across the bridge.
  4. We watch and take notes as the bridge collapses into a fireball of destruction.
  5. We order the drones to sweep up all the damage and recycle all the debris.
  6. We analyse the results, tweak the design, and set the drones building again.

It’s such a fantastic situation to be in. And yet, once we have a design we’re happy with, there’s a nagging feeling it’s only guaranteed to work for the tests we ran. So, we know it passes tests for situations in the domain of ‘obvious’ or ‘required’, but we’re limited to what we think is possible. And that’s scary. Would I be happy driving across a bridge that had stayed standing through a hundred thousand tests with cars, trucks, and buses? I’m not sure. Did they verify against high winds? Was there a scorching day during certification, and did it ever snow? Nobody did the maths on whether the bridge should stay up under such circumstances.

It’s not that we don’t think about what could happen in software, but we are convinced we can’t do the maths for all cases. It’s impossible to think of all the situations software could get into. So, we do our best, write many tests, and hope that’s enough.

Or we go deeper. We can use the computer to debug itself. We can verify APIs with QuickCheck, and model checkers can find bugs in concurrent code we would never have considered. Fuzzers help us find ways to break out ingest algorithms and protect us from hackers by leaving fewer gaps for them to exploit. Using the computer’s unswerving diligence and boredom-proof brain gives us a chance to find these imperceptible hazards.

There is a big difference between development as a construction process and development as a design procedure. The final objects have different qualities. Design development has the guarantee that it works for the intended use but has little or sometimes explicitly no warranties about its suitability outside those strict requirements. How many licenses have you seen where there is a clause disclaiming liability for any problems caused by software usage? Probably more than you think, as only a few people read the end-user license agreement, but it’s hard-coded into many open-source licenses.

We know we can’t run exhaustive tests when developing as a construction process, so we build with tolerances and reject unverifiable designs. But because we’ve done the maths, the final form comes with a 20-year materials and labour guarantee. An actual warranty, where we accept liability for any damages and losses incurred during proper product usage.

Personally, I am not going to buy a house sold under an MIT license, no matter how many unit tests they ran on it.

Inspection does not improve the quality, nor guarantee quality. Inspection is too late. The quality, good or bad, is already in the product. As Harold F. Dodge said, “You can not inspect quality into a product.”

— W. Edwards Deming, Out of the Crisis[Crisis82], p. 29.

Iteration speed is a valuable tool in getting to a good design, but we have to verify we’re using good metrics, otherwise we can fall into a pattern of positive testing. We must not just test that the code does what it should when used correctly but also verify it does not do what it shouldn’t when misused. Here, the ability to construct quickly pays off massively. We can confirm that our tests work with mutation testing—build something different and prove our tests fail, demonstrating our tests add value.

The difference in speed means that our process of adaptation is different. Instead of making things that are wholesome in their space and adapt easily, we make things that are good instances and make easy-to-tweak designs for their production. We value the ability to accommodate new features, capabilities, tolerances or to heal vulnerabilities. So, instead of working with looser materials as Christopher Alexander did, we work with hard, even brittle materials like the strict mathematics of cryptography, comfortable in the knowledge that they can be changed and restructured on a whim.

In software, the tricky part to modify isn’t the product but the design structure. The materials might be fungible, but the value in source code is not just in what the configuration produces but also in the familiarity of the arrangement to all individuals involved in its development.

Home

Home is not a house, dorm, or bed but a feeling of safety—the space to dream[TPoS58]. Home is our comfort and the beginning of each thought. When we are pushed to criticise home, we do not like it. People have many homes in their lives; a workplace or a park can be a home for the role they play in the world. Each aspect of us knows a home. Even if where we live is not perfect, we find one nook that we can trust and fit our most intimate selves there and relax. Programmers often feel this way about code ownership. I wrote it, I maintain it; therefore, it is a familiar home to me.

Sweeping changes are stressful because they make the codebase unfamiliar to many invested inhabitants. I equate this with a messy desk or workshop. When someone helpfully tidies it up, you can no longer find anything. When my parents took to cleaning my bedroom in my short absence as a young adult living away from home, I felt invaded. It was no longer my space. I did not feel I had permission to make further changes. When a code module I maintained for a year was suddenly subject to a series of pull requests making substantial changes and aligning it with a different module, I felt I had to either push back or take it on the chin and recognise the code was never my own. I had built my home on a right-of-way. It belonged to the project, and my familiarity with it was for me alone.

This is and always will be the strange habitat of code. The coder lives in the codebase for so long, and then suddenly, the product, the construction, is accepted. The codebase is vacated. You finally build the best possible environment to work in to solve the problem now it is understood—and with its success, the world is void of purpose.

It not only happens at the scale of the project but also a room at a time as components are developed and finished. All this is true unless you reuse, extend, and maintain the product. But even in iterative product development, there will always be a time when there are people leaving the project. For each of them, they are leaving home—a familiar dwelling and its associated safety.