Seven egregious failures of modern web tech

The modern web is a miracle of engineering, but its history is littered with brilliant concepts that flamed out in execution. For every innovation that stuck the landing, there is a promising technology that fell on its face. Each of these failures offers an object lesson for us as software developers. 

New tech is kind of a compulsion. We love to gaze at the shiny new frameworks on the horizon, but true architectural wisdom comes from examining the wreckage. And from catastrophic version migrations and hostile corporate takeovers of HTML to ignoring the realities of web physics and the physical limitations of the front end, we have plenty of wreckage to learn from.

Here are seven of the most egregious failures of execution in modern web history—and the architectural lessons we must absorb to ensure our good ideas don’t suffer the same fate.

Web SQL: A single-vendor dead end

The Good Idea: Bring a robust, relational database directly into the local browser. Enable responsive, offline-first web apps. Sync it all with a back-end data store of record.

The Fatal Flaw: External standards politics. Apple pushed Web SQL, but it was essentially just a raw wrapper around SQLite. Google baked Web SQL into Chrome, but Mozilla and Microsoft balked because standardizing it meant tying the entire web specification to one specific C library. It was deprecated.

The Lesson: Standards require consensus. Tying web infrastructure to a single implementation is a recipe for sudden deprecation. Although developers lost Web SQL and suffered under the clunky IndexedDB, the field has finally progressed into more fertile fields with the Wasm-based PGLite and more recent local-first solutions like PowerSync.

Angular 2: Burn the ships

The Good Idea: Build on the success of Angular with a completely rewritten, better version.

When Hernán Cortéz famously burned his ships, it turned out to be a brilliant strategy. For a mainstream web framework? Not so much.

Angular.js was the undisputed king of single-page apps (SPA), but it had performance bottlenecks. It felt like a high-functioning kludge. Google wanted to introduce a component-based architecture that would make it maintainable, enterprise-friendly, and performant. But to do it, they had to first tear it down to the studs.

The Fatal Flaw: Bad implementation strategy. Google announced a complete, non-backward-compatible rewrite that fundamentally broke everything. There was no clear migration path for massive enterprise codebases.

That left the door left wide open for a new framework. React came through that door and never left.

The Lesson: Never break the migration path. Even a difficult path respects your current users, telling them the developers value their continued participation.

Facebook’s Flow: Hothouse tomato

The Good Idea: JavaScript needed type safety to satisfy the enterprise. Flow introduced a granular type inference that could theoretically protect massive codebases with minimal manual annotations.

Unfortunately, the project was a hothouse tomato. It was conceived and nurtured in the controlled corporate environment of Facebook.

The Fatal Flaw: Flow was built for Facebook’s internal environment. Outside of Meta, Flow was notoriously buggy, required a heavy background server, crashed on Windows, and ignored the broader open-source ecosystem. Microsoft stepped adroitly into the breach with TypeScript.

The Lesson: An open ecosystem and seamless developer experience will always beat advantages like first-mover and raw technical superiority. Even if you’re a mega-corporation, keep the project tethered to active, broad use.

Google AMP: The corporate flex

The Good Idea: As mobile became massive, the web struggled to bring a decent experience to the handheld device. The entrenched modes we had cultivated over the previous 15 years were insufficient, leading to slow and clunky mobile websites, laden with heavy bundles and unoptimized assets.

Google AMP (Accelerated Mobile Pages) was intended to be a standard approach that pared down the HTML, the JavaScript, and the images served to mobile devices and enforced a universal CDN (content delivery network) cache. Google had the clout to accomplish all this.

The Fatal Flaw: Google relied on coercion to make AMP succeed. Moreover, the technology itself was too rigid. Google tried to force publishers to use a proprietary, stripped-down subset of HTML by threatening their search rankings. It was an anti-competitive, anti-innovation nightmare. 

The Lesson: Open web standards win. Vendor lock-in disguised as “performance optimization” will eventually be routed around and rejected by the community.

You may not be working in a global powerhouse, but similar kinds of things happen even in small and medium shops. When the organization tries to enforce rigid standards on the ground-level coders, it can produce friction, resentment, and rebellion. Top-down edicts rarely go smoothly in software.

Runtime CSS-in-JS: The performance illusion

The Good Idea: CSS at scale is notoriously difficult. Global namespace collisions and specificity wars have plagued massive codebases for decades. Colocating styles directly inside JavaScript components felt like a revelation. It encapsulated the logic, eliminated dead code, and made managing styles across distributed enterprise teams incredibly intuitive.

The Fatal Flaw: We ignored the underlying platform. In exchange for that beautiful developer experience, we accepted a fundamentally flawed runtime implementation. We spent five years forcing browsers to download massive JavaScript bundles just to calculate and inject styles on the fly during the render cycle. We took something the browser does natively at lightning speed—parsing style sheets—and forced the single-threaded JavaScript engine to do it instead, crippling initial load times and chewing up mobile CPU performance.

The Lesson: Never trade user performance for developer experience. When architectural abstractions fight the native capabilities of the browser, the end-user always pays the tax. We eventually had to swallow our pride and remember that browsers are highly optimized state machines for parsing native CSS. This hard lesson has led the industry back to CSS Modules, modern native CSS features, and zero-runtime compilers like Tailwind.

Micro front ends: Right architecture, wrong place

The Good Idea: Apply microservice-style decoupling to the front end, allowing large organizations to increase agility by spreading the development of different UI features across different teams.

Breaking the monolithic UI into separate, smaller components that could be developed, tested, and deployed independently promised the same benefits as microservices did on the server side: autonomous teams, smaller codebases, easier maintenance, incremental updates. We could all work freer and move faster. But what about the poor end-user?

The Fatal Flaw: We took a distributed back-end pattern and forcibly applied it to the browser. It didn’t really make sense. Micro front ends solved an organizational problem, but created complexity, massive overhead, and performance issues on the end-user’s device. Instead of a cohesive application, teams ended up shipping multiple JavaScript bundles, duplicate dependencies, and occasionally entirely competing versions of UI frameworks onto the same page. The browser was forced to act as a distributed systems arbiter, leading to fragmented states, performance degradation, and meta-complexity.

The Lesson: Conway’s Law should not dictate your client-side bundle. Just because a distributed architecture solves back-end scaling bottlenecks doesn’t mean it belongs in the client. You should never degrade the end-user experience to solve a problem within the corporate org-chart. If you find yourself flirting with a solution that introduces complexity, defer to common sense.

Instead of micro front ends, what we really needed was ECMAScript Modules and modern buildless infrastructure.

Client-side-only SPAs: Distributed computing strikes again

The Good Idea: Use the browser as a platform to deliver a thick-client, native-like experience. Manage state locally, reactively.

The Fatal Flaw: Whenever you replicate state, you introduce the problems of distributed computing. This is inevitable on the web. The client requires state to be useful to the user. In single-page apps as commonly understood we have a JavaScript engine running the user’s state and syncing it with the back end through JSON.

An entire architectural layer is devoted to translating JSON messages between the clients and the data store. Much of the business logic is concentrated in the client. The client is smart, the server is dumb.

The Lesson: The server exists for a reason. The industry just spent the last five years building massive meta-frameworks just to crawl our way back to server-side rendering using Next.js and similar full-stack frameworks.

Cautionary tales

It’s not the thing you see coming that gets you. It’s the thing you didn’t think about. It is often hubris or over-enthusiasm that leads us into the dark places. Advanced technical know-how and avid can-do may be yoked to flawed circumstances. Only vigilance will keep software projects from going sideways. One must continually check in on how implementations are actually going, not how the plan says they should.

If the technology heavyweights in this list can be overtaken by such unfortunate results, we must acknowledge that it can happen to us. That acknowledgement is itself the best insurance policy.

By jawad