We love to make abstractions. Human beings understand things in terms of abstractions, especially in terms of metaphors and similes. When we encounter something new, we find ways that it is like something similar. Eric Evans makes some great points about this in Software Is (Not) Like That, an article on DDD from way back in 2004.
Evans points out how ridiculous it is to pretend software is like manufacturing:
Before there were factories, crafts-people created useful objects, which were relatively costly and of variable quality. If there had existed the ability to effortlessly replicate objects created by the world’s best crafts-people, would we ever have had factories? We don’t need software factories.
and the destructive consequences of pretending building software is like architecture:
Smart, experienced people become incompetent through loss of hands-on practice….
The natural emergence of dynamic, creative design work squelched by remote idealists.
A programmer underclass established.
These illustrate the negative consequences of applying halfway-decent metaphors too broadly, and of applying bad metaphors at all.
The same problems apply to code. Take Object-Oriented Programming. (oh no, here I go again dissing OO. I promise, I’m only dissing the initial hype.) When OO was new, it would solve all our problems by allowing us to think of software in terms of concrete metaphors. Everything is a noun. We like nouns! We can hold nouns in our hand, turn them over and look at them, even pitch them at your head if you try to make us let go of our favorite metaphors.
In some domains these metaphors are useful, but taking them too far is destructive. As Eric points out toward the end of his article, metaphors can be useful for conveying information when you keep them small. We need to be very quick to discard a metaphor. Let it make its small point and then drop it.
Personally, I enjoy carrying a metaphor as far as I can and then much farther, until it becomes ridiculous. Once it is clear that the metaphor is ridiculous, there is less temptation to hold on to it.
There’s another point here. Metaphors are a form of abstraction, and abstraction is necessary for broad understanding. However, metaphors are super appealing because they’re concrete. Like those darn nouns in OO development, where in our training courses we modeled people, pens, chairs, things we can hold in our hands and throw. The best abstractions, the ones that we are less tempted to cling to until they become ridiculous, are more abstract abstractions. Design patterns do this. For-programmer DSLs often do this. As developers, we’re smart. We can conceive abstractions that aren’t named after something we’ve seen before.
Evans’s article mentions that in real modern factories, productivity comes from small teams on the manufacturing floor given some independence and self-determination. In an architected software system, the programming-team innovation that’s quashed in the name of uniformity. There’s a theme here: smallness. The best abstractions aren’t good for everything. They’re great for one specific thing, and then they stop. The best abstractions usually aren’t concrete, because software is not concrete.
Metaphors may help in our understanding of programming methodologies and of the software itself, but they should be quickly discarded. They’re each a stone on the path to understanding, where we can talk about the problem domain in its own terms.