My thoughts on modern software bloat

Published at May 9, 2026

I recently learned about a concept that has been plaguing modern software for a while now, and that concept is known as Wirth’s Law, which states that software is getting slower more rapidly than hardware becomes faster. It serves as a sobering counterpoint to Moore’s Law. It has essentially been a concept since the 90s ever since the late Niklaus Wirth of Pascal fame came up with that term, but only recently have we started to see the consequences of that first hand. Hardware keeps on improving year by year, but our software not only has gotten more slower, it has also gotten much more buggier. React apps that are stuck in re-composition loops have been shipped to production by large companies, and it has gotten more and more acceptable for big corporations to add more and more overhead to the software they ship, used by millions around the world (Windows 11’s start menu essentially being rendered by web technologies), which not only has negative effects on user experience (the new start menu anecdotally always has a delayed launch time as compared to previous versions of Windows), but also prove harmful to the environment long term. Billions of compute cycles are being wasted every day, in service of flashy animations and frosted tinted glass aesthetics. It seems that as hardware has gotten more and more powerful, we seem to ask much more from them. Software are stuck computing logic that might not be as meaningful to the user as much as they think, and we are essentially back to square one. The start menu not only negated decades of semiconductor development, it has also negatively regressed in terms of performance. Humans are very sensitive to input lag. If a program from 1998 responded in 10ms and a modern app with 1,000x the features responds in 50ms, the modern app feels slower to your brain, even though it is technically doing vastly more work behind the scenes.

But it wasn’t always like that. Wirth’s Law was not really a thing as back before 2010s you could actually feel software becoming faster, but from the mid 2010s to now you barely feel any increase in app launching speed, or the responsiveness of modern web apps. In the mid-2000s, hardware hit a power wall, and manufacturers switched to multicore architectures. A huge portion of the software we use daily moved from being native to being web-based. Many desktop apps (like Discord, Slack, or VS Code) are actually instances of the Chromium browser running JavaScript. JavaScript is significantly slower than native code. We traded execution speed for development speed, essentially spending the hardware gains of the last decade just to run a web browser inside our apps. This is effectively Jevon’s Paradox but in computing. As hardware has gotten better, developers were finding out that they could afford to be more lax when it comes to writing software, and the development experience has meaningfully increased as a result. Sharing code for both your website and your mobile device is inherently much more convenient, and CSS is infinitely much more flexible and easier than whatever bespoke solution some native UI frameworks came up with over the years. Frontend developers started speaking the same language, hiring got easier as a result, and who can resist the allure of modern TypeScript type inferencing with its loose but powerful structural typing with modern affordances like hot-reloading. An average web app is doing so much accounting in the background that the user is not privy too, firing off so many network requests and so on. Developers are also quick to disregard rendering time as long as it did not make the product unusable. Frameworks like React or Next.js often send a pre-rendered HTML page for you to look at, but then the browser has to hydrate it, by downloading and executing a massive JavaScript bundle to make the buttons actually work. This is why you can sometimes see a page but can’t interact with it for several seconds. React apps also often maintain a complex virtual version of the UI in memory. Every time something changes, the app performs a diffing process to figure out exactly which part of the real screen needs to update. While efficient for developers, it’s a constant tax on your CPU cycles. Because web developers can push updates instantly, the incentive to ship a perfectly tuned product is gone. The mindset has shifted to “Move fast and break things,” where lag is considered an acceptable trade-off for getting a new feature out the door as fast as possible. Also, can I mention how many unnecessary features modern apps built by big corporations have, even those that customers dislike. It’s almost as if a product is never done and relegated to maintenance mode. How about we take a chill pill for a sec?

A significant portion of those network requests are also spent on telemetry and analytics. The app is constantly reporting back on where your mouse is, what you clicked, how long you hovered, and your device specs. For some reason, modern companies have reason that they could not improve their products without those analytics, and proceed to do nothing with them, with their “big data” sitting around in their data lake or whatever people call them these days, never to be touched. Privacy concerns aside, this is essentially hobbling many products which when removed, actually makes them usuable again (easily demonstrated by the use of ad-blocking tools).

I know I’ve ragged on React a whole ton back there, but my point is not to raise pitchforks at React or those improving the JavaScript ecosystem. People argue that it’s the language choice that makes modern programs slow, but I’ll counter that with the premise that modern JS is extremely fast, but developers are always able to find methods to make even the fastest languages slow. Inefficient code caused by siloed development leading to developers having an incomplete view of the entire project develop insufficient mechanical sympathy to how the project works underneath, and hence create unnecessary operations, even when they don’t mean to. The overuse of frameworks and poor technical documentation amongst frameworks like Spring cause time crunched developers to do things the unidiomatic way, leading to poor code quality and readability. Bad algorithm choices also limit performance in a way that no language could fix. A developer working on a single microservice or UI component treats the rest of the stack as a black box. Because they don’t see the database logic, a dev might write a simple loop that unknowingly triggers many separate network requests, even when the code appears to be cleaner or more straightforward. When documentation is dense and deadlines are tight, developers copy-paste the first Stack Overflow answer that works. It’s also not uncommon to see stack traces in Java filled with millions of stacks of classes all suffixed with phrases like manager or factory each being only a few lines long and filled with absolutely mundane logic. It’s a wonder that the JVM is able to cope with all that and not crumble into dust. This leads to a culture of developers feeling guilty that they do not have enough abstraction, and that their code appears too simple.

So my hot take on this issue? Stop trying to blame frameworks or languages all the time (only some of the time), and start blaming the decision makers (and yes that includes us developers), cuz for all I know I unknowingly added so much crud into so many company codebases, that blaming the tools we rely on is like putting the cart before the horse. I can squeeze out a turd written in Rust if I wanted to. We need to be more discerning when choosing architectural patterns technologies such that they best fit our use case, and not necessarily chase the new and shiny who have yet proven their worth only to corner yourself in some bad architectural decisions.