Down On The Upside — Kevlin Henneypdf-download epub-download
There are many things about software and its development that appear to be back to front, inside out or the wrong way up. Take, for example, the case of the common tree. We have hierarchies for directories, for function calls and for class inheritance. We refer to these structures as trees. And where is the root? Out in the open, highly visible and at the top. The leaves proliferate at the bottom, often obscured, folded away and hidden from immediate view. Never mind the colour (red-black?), this orientation is far from tree-like.
Like the classic experiment where subjects are asked to wear prism glasses that invert their view of the world, we adjust. What used to appear upside down now appears normal. We cease to notice the difference. In the case of trees this is not really a problem: the properties of the abstraction are more useful to us than perfect fidelity against the metaphor. The inversion is simple enough not to be confusing, and it is rarely misleading.
Which leads us to the concept of abstraction and the way it is often used. This flipped view of the world is not always so free of problems.
Consider first of all what abstraction is: the act or result of omitting or taking away. We can consider problems, solutions, models of problems, models of solutions and so on without becoming lost in unnecessary detail - detail that has been abstracted. Different abstractions take different points of view, omitting certain kinds of detail in order to emphasise others. While the practice of abstraction is intrinsically neither good nor bad, we may judge the outcome in such terms: a good abstraction is a simplification that allows us to reason about a concept or work with a design more effectively; a poor abstraction is one that misleads us either by omitting necessary detail or by including unnecessary detail, drowning signal in noise. It is often mismatched abstraction that leads us astray: using a crowded class diagram beset with operation and attribute minutiae where a sketched package diagram would have been more useful; using a programming language designed for science and engineering to do systems programming; using the London Underground map as a guide to London's overground geography. What, then, is so upside down about abstraction? In constructing a system we often stack different abstractions upon one another as appropriate, leading to a layering of abstractions. The issue arises when we shift from speaking about layers of abstractions to levels of abstraction. These two expressions are not synonymous and have quite different implications. Although there is extrinsic ordering, the former does not imply or require any intrinsic ordering. The latter, however, strongly suggests that the abstractions have an innate ordering. This is not necessarily the case, although it may sometimes be true: a perspective that leaves out more detail than another perspective can be considered more abstract. It might be better to refer to this ordering property as degree of abstraction. Another aspect that might be ordered is granularity. Sometimes, when people speak of levels of abstraction, they are referring to granularity of abstraction, which may be considered a more precise description.
In many cases there is no obvious ordering, but people nonetheless impose one, often by implication. For example, some might argue that FORTRAN 77 is a higher-level language than C because it is organised around arrays and operations on arrays, useful for many science and engineering applications, and it doesn't have a model of memory locations and management. On the other hand, some might argue that C is a higher-level language than FORTRAN 77 because it supports structured control flow, user-defined data types, data abstraction and dynamic memory management. The benefits afforded by each language's abstraction choices are almost entirely complementary in nature, which makes any kind of total ordering between the two languages highly contextual and, in many cases, personal. I know where my preference lies, but that's not relevant here: what is relevant is my personal experience that confirms that attempting to use FORTRAN 77 for systems programming is a tedious and error-prone experience - a painful and clumsy lesson in misaligned abstractions - when compared to working in C.
The problems in discussing and reasoning about layers of abstractions are compounded by a perception of altitude, the tendency to talk about higher and lower, with an implied judgement that higher level equates with better and lower level equates with worse. It is in this sense that the inverted view of the world becomes noticeable. We are offered domain-specific languages, analysis models and domain-driven design as being high level because their abstractions are closer to the domain of the user than, say, bits and bytes, which qualify as lower-level abstractions. Therefore, these approaches are better for working closely with users and customers. The stated goal is that we should be thinking more in terms of the problem domain - high level - than the solution domain - low level.
Wait a minute. If this is the goal, it is something of a terminology own goal. While the intent is well founded, and the practices sound, the words are the wrong way up.
Talking about the problem domain as being at a high-level of abstraction and the machine domain at a low-level betrays an ingrained bias. If abstraction is an act of omission, what is it that is being left out when we say high-level of abstraction? What is it that is being abstracted? Machine-level details, the bits and the bytes, the programming-language types, etc. Techies might never question this, but users hold a very different point of view: the world in which they carry out their business is significantly more concrete than the abstract realm of software. Talking about the user domain in terms of concepts familiar to users involves, from the user perspective, little or no abstraction. The further you go into the domain of software the less real and more abstract things become. It is the real world and the associated problem domain that are gradually omitted.
We need to be more careful with the assumptions entrenched within common terminology and visualisations. If you consider the world of the machine as the concrete starting point, the world of the customer is more abstract. If you consider the world of the customer as your concrete starting point, the world of the machine is more abstract. So, if you're trying to come across as genuinely customer-focused, user-centric and domain-driven, you need to be low-level rather than high-level. Abstraction is not so much a matter of altitude as a question of your starting point and your distance from it.