Software often eludes analogy. It’s written in code, compiled into assembly, translated into CPU instructions, run on a kernel, and finally executed on invisibly tiny transistors. Such a complex beast is hard to map onto the real world.
The analogy we’ve settled on for the creation of software is the architect/builder separation. The designer is the architect: he provides a specification for the product. The programmer is the builder: she implements it. However, this formulation is functionally a myth, and understanding why it’s wrong will help explain why software is delivered late, low-quality, and over-budget.
This koan on the Codeless Code is an interesting one. In addition to being cute and snarky, it makes a very strong case that the civil engineer and the software engineer do very different things. We know that the designer is not doing the building; if programmer is also not doing the building, how is software turning from idea into reality?
What is happening is that the designer presents the software as very high-level blueprints to the programmer. The programmer then takes those and creates a lower-level set of blueprints for the compiler.
(Incidentally, the compiler is producing an even lower-level blueprint, called the Intermediate Representation, which is translated in to a final set of blueprints, the specific instructions for different CPUs. It’s blueprints all the way down.)
The compiler takes the programmer’s blueprints and arranges them (nearly instantly!) into their final form. The actual “construction” phase of software engineering is effectively free. To understand how fundamentally strange that is, imagine a machine that accepts blueprints for a bridge and instantly produces the whole bridge. The completed bridge takes up practically no space so we can produce as many copies of it as we want. In addition, our machine can produce other physical constructs to poke and prod the bridge to make sure it works as expected. That would be a very weird world for civil engineers indeed!
This new analogy helps explain two things about our industry. First, it helps explain why requirements change all the time. People have seen how powerful code is, and how quickly it can be changed. It’s also hard to explain in advance why some changes are much more difficult to make than others, so requirements will change in the process of creating the blueprints. Nothing is final until the “Submit to App Store” button is pressed.
The other thing that this analogy helps explain is the “mythical man month”. Bringing on another programmer paradoxically slows the project down. You can add extra builders to a bridge to build it faster, just as you can add extra clock cycles or cores to a CPU to make it compile faster. But nobody has ever suggested that architects are fungible. Smaller teams produce higher quality code for this reason. The “architects” aren’t isolated, given a rote task, and managed in a top-down fashion. Designing software architecture takes omnidirectional communication, which gets costly as teams grow.
What else can we learn here? Because the designer’s “blueprints” are interpreted by a human, any inconsistencies can be smoothed out. The programmer’s blueprints have to be much more detailed, since they will be interpreted literally and unambiguously by a CPU. It pays to have more explicit blueprints earlier in the pipeline, because the programmer will have to do less interpolation to fill those gaps. Creating those specifications will result in better software, and can help with reducing requirement creep.
Because computers only emulate the real world for convenience’s sake, it can be hard to remember how many layers of abstraction lie between the code you write and the actual silicon that runs it. In Structure and Interpretation of Computer Programs, Abelson and Sussman say:
A computational process is indeed much like a sorcerer’s idea of a spirit. It cannot be seen or touched. It is not composed of matter at all. However, it is very real. It can perform intellectual work. It can answer questions. It can affect the world by disbursing money at a bank or by controlling a robot arm in a factory. The programs we use to conjure processes are like a sorcerer’s spells.
It’s not valuable to think of software as a bridge; it’s too weird for that.