What kind of updates do we consider major? Note that I am not talking about a SemVer major. I'm talking about something that we typically only do to a framework maybe once every few years, right? The common reasons for such major updates include, first, to correct architectural design flaws. Second, to introduce fundamental new capabilities, and three, to shed technical debt of the existing architecture. Note, these usually involves mass refactoring or even ground-up rewriting, which was the case for view three.
The common traits of these core reasons are that they are extremely expensive to do in an incremental fashion, right? Because some of the issues are rooted in the architecture and without overhauling the architecture, some of the improvements were simply not possible in the first place. So, doing such big updates while retaining fully backwards compatibility is sometimes just prohibitively expensive to do, right? Why, because full backwards compatibility is a burden that compounds with every major new change introduced. The more ambitious the new changes are, the more technical debt will incur during the process.
In the long run, it will make the process even harder, adding new features, much harder. And most importantly, it becomes more and more costly to maintain software in the long run. Now on the other hand, we can reduce the scope of changes in order to make things more feasible, but this also results in less ambitious improvements, fewer possibilities explored and potentially stagnation. So it's almost like there are a bunch of knobs that you can try to turn, but when you turn one of them, the other ones will move in reaction to the one you're turning.
So, here I visualized some of the factors that we have to consider while doing major updates into four knobs, right? These are backwards compatibility, how easy it is to upgrade, the cost to implement and maintain the changes and maintain it for the long run, and finally, the level of improvements these changes can bring about. So, in the case of Vue 3, the example is if we turn the backwards compatibility to 100%, this will make it extremely easy to upgrade, but it'll also significantly increase the implementation and maintenance costs. And if we try to push the scale of improvement up to 100% at the same time, it will drive up the cost to nearly infeasible scale. Now, if we turn the compatibility knob down a little bit to 90%, we can now have both reasonable cost and somewhat major improvements, but user upgrade will suffer, right? It will become more difficult to upgrade.
This essentially sums up the trade-offs that we have opted for in Vue 3, right? We tried to keep the majority of the framework concepts and APIs intact while introducing new capabilities. So the API is 90% compatible, it's not 100% compatible. Most importantly, some of the internals have changed, right? But we were able to bring major updates in almost every aspect from performance to bundle size to internal architecture, long-term maintainability, TypeScript integration, right? It's an improvement across the board. Unfortunately, we also had to introduce some of the small breaking changes. Many of the public API changes are now covered in the compact build. However, some of the exchanges are more fundamental, for example, the switch from using ES5 getter-setters to proxies for the reactivity system or changing the underlying virtual DOM format. These changes were necessary for the level of improvements that we were aiming for. However, they also made it more challenging for existing projects to upgrade, especially apps with external dependencies that rely on Vue 2's internal behavior. This is the biggest blocker that we have seen in practice.
Now, I'm not trying to look for excuses by talking about all this. Looking back, we probably could have done some things a lot better, especially with the breaking changes to make the upgrade process smoother. We could have introduced a compact build earlier and we definitely should have worked on the new docs earlier as well. But ultimately, I still believe making Vue 3 100% backwards compatible, especially with other libraries that relied on Vue 2's internal behavior, is something that was just too costly to commit to. We won't be able to get the level of maintainability and the level of improvements that we want, that we have right now at the same time, if we commit to 100% backwards compatibility. So, enough about the breaking changes, but now let's talk about something more optimistic.
Comments