This principle builds on the layering principle, and deals with a common decision point that most software developers reach many times in the course of their work.
The situation that leads to this point unfolds something like this. There is some code at the lower layer that isn’t giving us the results we need for implementing the functionality of our layer. There’s some wart that was left there by developers of that layer, and we have to do something to minimize the exposure of our customers to this wart.
What do we do? The most intuitive action to take here is wallpapering: adding some code at our layer to reduce the gnarliness of the wart. This happens so commonly and so pervasively that many writers of code don’t even recognize they are doing it. Web development has a proud tradition of wallpapering. There are entire communities of libraries (jQuery, React, etc.) that invested a ton of time into wallpapering over the warts of the Web platforms.
Especially when we are not thinking in terms of layering, we might just presume that we are simply writing good code. However, what is really happening here is a shift in layering responsibility – or perhaps a “layer entanglement” is a more catchy term. The code we are writing to fix the wart is out of place in our layer: it actually needs to live at the lower layer. And that means that by wallpapering, we are most definitely violating our layering principle. The code we write might be astoundingly good, but it’s kind of jammed sideways between the two layers.
As a result, the wallpapering code tends to be a drag on both layers. The layer below, now constrained by the specific way in which the wallpapering code consumes it, is grumpy about the loss of agency in addressing the original wart. By wrapping itself over the wart, our code now amber-ified it, preserving it forever.
At our layer, the code is an albatross. I already pointed at the CSS Selector-parsing code in jQuery as one example. Because it belongs to a lower, more general and more slowly moving layer, every wallpapering code saps efficiency of the team that needs to maintain it.
Perhaps most importantly, the wallpapering code has the capacity to misinform the layers above of the nature of the machinery below. If the opinion of the wallpapering code deviates strongly from the lower layer’s intention, the consumers at higher layers will form inaccurate mental models of how the lower layer works. And that is where the compounding costs really get us in the long term. The story that my friend Alex Russell has been telling about the state of modern web performance is a dramatic and tragic example of that.
All in all, we are best to avoid wallpapering at all cost. However, this is easier said than done. Most of the time, our bedrock layers (the lower layers we’re building on top of) are imperfect. They will have warts. And so here we are at the primary tension that the wallpapering principle helps us resolve: the tension between the intention to avoid wallpapering and the need to deliver reasonable products to our customers.
To resolve this tension, we must first acknowledge that both of these forces have merit, and in extreme, both result in unhappy outcomes. To navigate the tension, we must lean toward minimizing wallpapering, while seeking to reduce the cost of opinion of our wallpapers when we must employ them.
The key technique here is polyfilling (and its close cousin, prollyfilling): when we choose to wallpaper, do it as closely to the spirit of the lower layer as possible. For example, if our cloud API is occasionally emitting spurious characters, we might be better off filing the “please trim those characters” bug against this API, and then trimming these characters as closely as possible to the code that receives them from the network. Then, when the bug is fixed, we just remove the trimming code.
A good polyfill is like a temporary tenant in an otherwise crowded family home: ready to move out as soon as the conditions permit. Wallpapering is usually a bad idea. But if we feel we must wallpaper, think of the code we’re about to write as a polyfill – code that really wants to live at the lower layer, but can’t yet.