In part one, I described how the web page — once a document containing facts, data, and interface together – has been hollowed out. What remains is largely just the interface. “View source” no longer tells you anything useful, and the web has stopped behaving like a medium for documents. It has become a distribution mechanism for software.
Now I want to talk about how the decision costs us every day.
The complexity problem
Once data was removed from documents, complexity followed.
What we now call "modern web development" is not one thing, but a stack of interdependent systems layered on top of each other to compensate for that initial separation.
Even for a simple application, the shape is familiar.
The default architecture
A typical web app today requires: a database to store data, an API server to expose that data, an application server to render or assemble responses, a JavaScript framework to manage UI state, client-side code to fetch, cache, and reconcile data, and infrastructure to host and scale each of these components.
Often there is server-side rendering, followed by client-side hydration. State exists in multiple places at once. Data is marshalled back and forth between layers that were never designed to be cohesive.
This complexity isn’t incidental. It’s baked in.
Once the document stopped being the unit of truth, everything was up for grabs. State, storage, validation, rendering: every function that could conceivably become a separate layer did.
Computational overhead
Each layer performs work that used to be implicit.
Rendering happens twice. Validation is duplicated. State is mirrored between client and server. Caching becomes a discipline rather than a property. Concurrency must be reasoned about explicitly.
The browser becomes a runtime environment, not a document viewer. The server becomes an orchestrator rather than a publisher.
For simple problems, this is a lot of machinery.
The cost is high
This complexity is not just conceptual. It is economic.
Every layer costs money to run. Databases incur storage and compute costs. API servers must be hosted, monitored, and secured. Application servers scale with traffic. JavaScript-heavy clients increase bandwidth and CPU usage.
There are ways to try to reduce costs. One database rather than a cluster. One API server instead of a load-balanced pair. Running it all on a single bigger machine, rather than a fleet of smaller ones. No matter what you do, even "cheap" stacks accumulate recurring costs.
As a result, there is now a minimum economic threshold for a website to exist. A project must justify its infrastructure before it can justify its purpose.
Beyond money, there is a cognitive cost. Modern web development requires holding multiple mental models at once, and even simple changes must be reasoned about across database, API, client, and deployment layers. The work is often not changing behaviour, but navigating structure.
Operationally, this compounds. Every layer is another place things can fail, another system to monitor, another question to answer when something breaks. For large organisations building complex products, this may be acceptable. For small tools, personal projects, or simple public pages, it is a disproportionate burden.
What this excludes
This economic floor quietly excludes entire classes of software.
Small web applications (tools built for one person, a family, or a small community) become hard to justify. The monthly cost of simply existing outweighs the value of the thing being built.
Small experiments die early. Long-lived personal tools never start. The web becomes a place for platforms, not individuals.
This was not the original intent. The web was designed to give individuals agency: to be producers of information, not just consumers. But today's web stack assumes scale from the outset. If you are not building for thousands of users, the economics work against you.
The inevitable question
None of this happened because developers wanted complexity for its own sake. These patterns emerged as pragmatic responses to real constraints.
Users wanted desktop-like responsiveness, and full page reloads felt slow and jarring, especially as native mobile apps raised the bar for what "snappy" meant. AJAX, and later single page applications (SPA), made interfaces feel more immediate.
An early argument for SPAs was that after the initial load, you'd transfer only data (small JSON payloads) rather than full HTML pages with repeated navigation chrome. This turned out to be more complicated in practice, but the reasoning was sound at the time. Even so, features like chat, notifications, collaborative editing, and live dashboards push hard against the document model. WebSockets and persistent client-side state made them tractable.
But it is worth asking whether the constraints themselves were inevitable.
If data had remained in documents. If documents had remained the unit of storage, transport, and meaning. Would all of this machinery be necessary?
The web already shipped with a structured data model. HTML is a tree. CSS selectors are a query language. The infrastructure for treating documents as data is there.
We just built around it instead of on top of it.
That question is where the next post begins.