We Haven’t Removed a Layer in Thirty Years

We used to write HTML, CSS, and JavaScript, and a browser rendered the result. If a page was slow, you could open the source, inspect the code, and trace exactly what the browser was doing. The stack was small enough to hold in your head.

It isn’t anymore, and it hasn’t been for a while.

jQuery, Sass, Webpack, React, routers, server-side rendering JavaScript frameworks. Each arrived to solve a real problem. And many of them solved problems created, or at least amplified, by the layer before them.

React made rich client-side applications easier to build. But single-page applications replaced the browser’s native navigation model with client-side routing, so we built routers to recreate it. Bundling solved asset management, but as bundles grew, we built code splitting to keep them from choking the network. Server-side rendering brought back faster initial loads and searchability, but reintroducing a server meant coordinating server rendering, client hydration, caching, and routing. An entire category of frameworks grew up just to manage that coordination.

Layer by layer, we didn’t simplify the stack. We moved the complexity somewhere we didn’t have to see it.

And now we’re adding agents and skills that generate code, that generates more code, which still has to pass through and add to that same stack before a browser can ever render it.

We haven’t removed a single layer. We’ve added another one whose job is to operate the layers underneath it.

I used to be able to open a page, read the JavaScript, and have a genuine sense of what the browser was going to do with it. Now I can write a prompt that generates a component, which gets transformed by a compiler, bundled by a tool I didn’t configure, hydrated by a framework whose defaults I didn’t choose, and ultimately rendered by an engine several layers removed from anything I actually wrote.

When it breaks, I’m not debugging the application anymore. I’m debugging a description of a description of code.

That’s the actual cost. Most of these tools solve real problems. The problem is the growing distance between what I wrote and what is running. Each new layer makes that distance a little larger, and a little more permanent.

We used to be able to answer “why is this slow?” by looking at the thing we built. Increasingly, we ask one system to ask another system to tell us.

Maybe this is just the next turn of a cycle we’ve seen before. SSR frameworks got built to claw back what SPAs gave away. Something will probably get built to claw back what this layer gives away too. That’s not a reason to stop, or even a reason to worry particularly. It’s just worth noticing that we’re not adding this layer to simplify anything. We’re adding it because it’s useful, the same reason we added all the others, and we’ll probably spend the next several years building tools to manage what it costs us, the same as always.

We’re not internet factories. We’re people who used to know, in detail, what we were building. I’d like to keep enough of that to notice when it’s gone.