When Web Frameworks Become Pyramid Schemes

Often, a web framework starts out simple-ish. It’s built to address a need, using a particular approach or mental model. You can quickly grasp what it’s doing; it doesn’t take long to ramp up and start using it.

But as a framework grows in popularity, more developers begin using it, in more situations. New edge cases and gaps in functionality appear that the creators didn’t anticipate.

At this point the creators have a choice. They can stay simple and true to the original design and accept that users will have to create their own workarounds, or they can expand the framework’s functionality and try to support as many use cases as possible.

Becoming “all things to all people” seems common for frameworks. Problem is, that’s impossible to do while keeping the mental model simple. And the more use cases that are supported, the more complicated the framework code becomes.

So what’s the problem? Why does a framework user care if the internal code is complicated? Isn’t the whole point of a framework that it abstracts away the complexity so you don’t need to think about it?

Well… no framework is a perfect abstraction. New web frameworks appear regularly because the platform they’re built on and trying to improve — the browser and HTTP — were not designed for dynamic web applications. Over time, improvements have been made in browsers, but they still present major difficulties in managing state and rendering the types of apps that people want to write.

Web frameworks attempt to let you write dynamic web apps in a “clean” way without having to worry about the underlying platform difficulties. But since the “clean” code is so far removed from what’s actually happening in the browser, frameworks need to do a massive amount of work under the hood just to support the abstraction. Since there’s so much complexity, there are many edge cases and situations where the abstraction doesn’t work, and new abstractions must be created to patch the gaps.

As more abstractions are added to the framework, more edge cases occur with each of those new abstractions, and the codebase continues to grow. Furthermore, developers are constantly creating and publicizing new libraries and tools. Many of those need extra configuration to work with a framework, so new packages are added to link the two, further increasing the amount of territory the framework occupies.

As the complexity of the framework grows, so does the amount of time and mental energy needed to both learn how to use it, and how to maintain code that uses it.

Eventually, it takes more time to learn and use the framework than it would have to write code directly for the underlying platform (i.e. using vanilla JavaScript).

So why is this like a pyramid scheme? Well, it’s much easier to understand code that you wrote (or that you wrote recently) than it is to understand code that someone else wrote. Even if you understand the overall philosophy of their code, you don’t know all the individual decisions they made along the way; you don’t know the intricacies of the mental model they used to construct the code. You can usually build your own mental model of their code, but that takes a lot of time.

They’ve got a head start on you. If they’re maintaining a framework, they’ve been spending time in, and adding to, the code for months or years. Whenever they add a new abstraction (which they inevitably do), it’s very clear to them why they’re doing it, how it fits into (and modifies) the existing mental model, which situations it works well for, when you shouldn’t use it, and all manner of other details. As for you, if you aren’t willing to spend the extra hours getting to know the framework codebase, you need to read their documentation. If they haven’t explained themselves thoroughly (which is almost impossible to do with code, especially if they want public documentation to remain accessible for most), then you either have to spend extra time in trial and error getting it to work, or you have to simply trust what they say without knowing why. The more times you trust without knowing why, the further you get from the underlying platform, and the more dependent you are on the maintainers’ descriptions and decisions.

That’s even more the case if your application code already uses the framework.

And if React (for example) is the only way you know how to build web apps, you become a React developer, and no longer a web or JavaScript developer.

If your platform is React instead of the browser, and you don’t understand those intricacies, your ability to produce performant, bug-free code is limited. If, on the other hand, your platform is React and you spend time understanding those intricacies, you’re spending precious time on a temporary, changing technology that you could have invested elsewhere.

The people who benefit most from a framework’s popularity are the maintainers. As their framework increases in usage, they increase in prestige. Other developers become more dependent on them for bug fixes and feature support, as well as for help understanding how to use the framework effectively. As the codebase grows, the barrier to entry for understanding gets higher. The more the framework is used, the more other companies and developers want to use it, and the demand for the maintainers’ support and guidance grows (not to mention their desirability for employment). The more widely used a framework is, the more companies and codebases will be affected by an update, and therefore the more power the maintainers hold. Similarly, those maintainers are also able to use this power to influence development trends and the trajectory of the industry as a whole.

On the flip side, for users of frameworks, it’s become almost taboo not to use one. If you write vanilla JavaScript, you hear remarks about spaghetti code and reinventing the wheel. It’s almost impossible to avoid using a popular framework in most companies these days, despite their shortcomings. That means modern web developers essentially have to pay the tax (in the currency of time and energy) of staying current with one or more frameworks, similar to a pyramid scheme.

Are framework maintainers doing this on purpose? Probably not. There’s nothing wrong with a developer who wants to maintain a framework and help others use it. (Although I do wonder if some corporations might have been aware of this phenomenon when they released popular frameworks.) However, when maintainers use their influence to represent using their (or any) framework as a matter of moral obligation, or say (or imply) that developers should use their framework and not “reinvent the wheel”, it can be misleading for inexperienced developers and harmful to the industry as a whole.

What’s the solution? I think ultimately the world would benefit from a better platform for web apps. Developers who learn their underlying platforms deeply (how browsers and computers work in general) will have the tools and skills to build something better instead of being constrained to perpetuate the status quo. That type of learning will also empower them to write better JavaScript in general.

And… deeply understanding how computers and browsers work enables developers to circumvent a lot of the time and effort that might normally be needed to learn a framework. If you understand the philosophy behind a framework, and you know how browsers work under the hood, that greatly reduces the number of possible ways the framework creators could have implemented their ideas, and it becomes easier to identify where bugs and performance issues will be likely to appear. And when the latest framework becomes obsolete, you won’t be left stranded.

Want more?

Get notified when I post new stuff.