There is a particular kind of afternoon, familiar to anyone who has kept a modern service alive, that is worth looking at plainly. A write occasionally lands twice. To find out why, you go down. The ORM was supposed to spare you the SQL, so you read the SQL it generated. The cache was supposed to spare you the database, so you reason about what it might be holding. The service mesh was supposed to spare you the network, so you check whether it retried. The operator was supposed to spare you the YAML, which was hiding the kubelet, which was hiding the container, which was hiding the process that, in the end, wrote the row twice. Every layer promised you would not have to look beneath it. To fix the bug, you looked beneath all of them, and you had to understand each layer on the way down as well.
This is the fourth of the four breaks the first piece named, and it closes the diagnosis. Last week we took the workaround: the container solved a language's inability to use its cores, and the industry promoted the workaround to an architecture. Today, the layers, which is the subtlest of the four, because layering is not a mistake. It is one of the genuinely good ideas in the field. The trouble is what a good idea becomes when nobody is paid to keep it honest.
The Promise a Layer Makes
Start with the idea at its best, because it deserves it.
In 1968 Edsger Dijkstra described the THE multiprogramming system in a paper that is still read for pleasure. Its structure was a strict hierarchy of levels, each built only on the one below, so that a programmer could reason about a single level at a time and trust everything beneath it as settled. The layer was a discipline for containing complexity: below this line, the problem is solved, and you need not carry it in your head.
Four years later David Parnas gave the discipline its sharpest formulation. His 1972 paper on decomposing systems into modules coined the term information hiding, and its criterion is the part worth memorising: a module should hide a design decision that is likely to change, so that when the decision does change, only that module changes. The boundary is drawn where the volatility lives. Draw it well and the layer is a promise kept: the thing below is bounded, it will not leak, and you are free of it.
That is the honest version of a layer. It bounds. It hides a decision that is genuinely settled behind it, and in exchange it asks you to know one thing less.
Where Containing Became Postponing
Somewhere between Parnas and the cloud generation, the verb changed. The layer stopped bounding and started postponing, and it broke Parnas's promise in both directions at once.
It stopped hiding a stable decision, because the thing below keeps leaking through. The ORM's SQL surfaces in the slow-query log the first time a page is slow. The cache's staleness surfaces as the bug report that cannot be reproduced. The mesh's retry surfaces as the write that landed twice. A boundary is only a boundary if what it hides stays hidden, and none of these do, because none of them hide a decision that is settled: they hide one that is live, and a live decision does not stay behind a line.
And it stopped reducing what you must know, because now you must know both. The layer was meant to let you carry one thing less; instead you carry the layer and the thing it was supposed to spare you, because when it leaks you are debugging both at once. A boundary you cannot see past, but must, is not an abstraction. It is a blindfold with rather good documentation.
There is a well-worn line, usually given to Phil Karlton and preserved for the rest of us by Tim Bray, that there are only two hard things in computer science: cache invalidation and naming things. It is funnier than it looks, because the modern stack has gamely volunteered to do both at once, and to do them by adding a layer: a cache, which must be invalidated, reached through a service, which must be named and resolved. The two hard things are not solved by the tower. They are what the tower is made of.
The Work Nobody Is Funded to Do
Why does the tower only ever grow taller? For that, the cleanest answer is fifty years old.
In 1974, studying the evolution of IBM's OS/360, Meir Lehman set down what became his second law of software evolution: as a system evolves, its complexity increases unless explicit work is done to reduce it. Note the asymmetry the law describes. Complexity accrues on its own, as a by-product of change. Reduction does not. Reduction has to be chosen, funded, and done on purpose, against the grain of every incentive.
Watch what that does to a layer. Adding one is easy to justify: it solves today's problem, it ships, it appears in the release notes, someone gives a talk about it. Removing one is almost impossible to justify, because it ships no feature, closes no ticket the customer filed, wins no conference slot, and appears on no roadmap. In the industry's accounting, removing a layer is indistinguishable from doing nothing, which is why it is the first thing cut and the last thing rewarded. So the layers accumulate, each defensible on the day it arrived, and the reduction that Lehman says the system needs is precisely the work nobody is paid to do. The plaster is cheap. The wound is not.
The Things That Were Allowed to Finish
The alternative is not to abolish layers. It is to bound complexity the other way: with things small enough to be understood whole and complete enough to need nothing wrapped around them. This is not a wistful idea. It is running, at a scale the tower rarely reaches.
SQLite is about a hundred and fifty-six thousand lines of C, shipped as a single amalgamated file you drop into a build, with no server, no connection pool, no ORM required to make it bearable. It is, on its authors' own careful estimate, in over four billion smartphones and something on the order of a trillion databases in active use, which makes it very probably the most deployed database engine on Earth. It bounds its complexity by being finished, not by being hidden. Where the standard stack would put a database behind a pool behind an ORM behind a cache, SQLite is one library you can read.
It is not alone, and the others are older. awk has done its one job since 1977 and is essentially the same tool today. sed dates from 1974, make from 1976, each small enough that it could be completed rather than merely versioned. pf, the packet filter, has been one configuration file with one coherent syntax since it shipped in OpenBSD 3.0 in December 2001: refined for a quarter of a century, never once replaced. These tools compose the Unix way, side by side through a visible seam, a pipe or a file you can inspect, rather than by stacking through hidden ones. A pipe is a boundary you can see through. A laminated layer is a boundary built so you cannot.
The same instinct scales to a whole system. A FreeBSD base is one source tree: kernel, C library, firewall and documentation built, tested and released together, so the pieces fit because they were made to fit, and there is no laminating layer needed between them to translate one project's assumptions into another's. That is the quiet opposite of the tower. It is not that it hides less. It is that there is less to hide, because nothing between the parts is a stranger. Boring, in the way that eighteen months of uneventful uptime is boring.
The Point
That closes the diagnosis. Four things broke at the same time, and we have now taken each on its own. The count was never justified: kilobytes do the work the industry bills in megabytes. The boundary was never drawn: node_modules has no responsibility line, and no scanner can add one after the fact. The workaround became architecture: a language that could not use its cores was answered with a container, and the container was promoted to a principle. And the layers hide what they should bound: a discipline for containing complexity became a habit of postponing the look beneath, stacked as high as Lehman's law predicts when no one is funded to bring it down.
They are four diagnoses of one system, and the system has three carriers that explain every break in depth: npm, the registry sold as a service; Docker, the workaround sold as an architecture; and the way we organise teams, which sets the whole arrangement in the org chart. The next thirteen Wednesdays take the carriers one at a time.
Next Wednesday begins the second phase: npm in detail, starting with the registry that was never a service but a market.