Every software system is more than the sum of its parts.
No matter how well we design each part of a system, there is always more work to do.
No matter how well we design the first-order interactions between those parts, there is always more work to do.
No matter how we package things up and split systems into subsystems, there is always more work to do.
No matter how easy we make it to swap one subsystem out for another, there is always more work to do.
What are we missing? It’s a question that keeps me up at night.
I keep thinking that it would be helpful to make a clear distinction between code design and software design. These two activities are often done side by side, and they influence one another, but they’re not one and the same.
When designing code, it’s possible and practical to think in terms of a bunch of black boxes all wired together. Each black box has a defined purpose to serve, and is capable of turning a known set of inputs into predictable outputs. It’s simplistic, but it’s a good starting point.
When designing software, we need a different mental model. We must instead think about how the things we build will operate in the wild. Because we can’t predict how humans and robots will poke at the surfaces of our systems, we can’t rely on known inputs and expected outputs as a way to validate our understanding.
It is hard to talk about concepts that we don’t yet have a common language for. This is part of what has driven me to look more closely at the work that has been done in systems thinking, in architecture, in UX design, etc.
No answers yet, only questions. But I’ll keep digging.