The critique of Micro Frontend
On 19 June 2019, Cam Jackson published an article called simply Micro Frontend.
Micro Frontend - An architectural style where independently deliverable frontend applications are composed into a greater whole.
The article in itself is good, but I have some serious doubts about the specific theses, so let’s go through them.
The old, large, frontend monolith is being held back by yesteryear's tech stack, or by code written under delivery pressure, and it's getting to the point where a total rewrite is tempting. (…) The endgame here is that we're afforded more freedom to make case-by-case decisions on individual parts of our product, and to make incremental upgrades to our architecture, our dependencies, and our user experience. If there is a major breaking change in our main framework, each [M]icro [F]rontend can be upgraded whenever it makes sense, rather than being forced to stop the world and upgrade everything at once.
The way I understand it: there is a bad monolith frontend project with a tech debt, and the reason it’s bad is the ‘delivery pressure’. A major breaking change in our main framework kicks in, so we need “to stop the world and upgrade everything at once”, and apparently that’s very tough. So we divide the project into “smaller, independently deliverable parts”, because it is assumed that it is easier to upgrade the project step by step, chunk by chunk. We assume that the “freedom to make case-by-case decisions” makes upgrades easier.
Why may these assumptions be wrong?
First of all, if that’s a major framework, then we probably share it across the chunks, so we can save some space: bundle size, network usage, and so on. This means we most probably need to update the whole project at once anyway. Even if we don’t share it, this means we can skip the upgrade, because a part of the project which doesn’t need it, will work anyway. Welcome to dependency hell. You probably think - how on earth teams wouldn’t want to make an upgrade? Teams might even want to upgrade, but let’s not forget about the ‘delivery pressure’ we mentioned before. They might not be allowed to do so. It’s very easy to omit an upgrade or postpone it, for the sake of delivering yet another super duper important feature.
The source code for each individual [M]icro [F]rontend will by definition be much smaller than the source code of a single monolithic frontend. These smaller codebases tend to be simpler and easier for developers to work with.
But only in the beginning! I see it this way: before there was one monolith project, now we have a couple of smaller projects, and each of them tends to expand by adding new features or by maintaining existing ones (it’s “simpler” now, which means it happens much more often). Nothing stops that expansion, so in the long-term perspective the project may end up with “smaller” projects, and each of them is of the same size as the original monolith! To back it up, guess who’s working on those new smaller parts of the project? Most often the same developers who did the mess in the first place! Why do you believe they won’t do that again?
Then we read later:
(…) a single, high-level architectural decision (i.e. "let's do [M]icro [F]rontends"), is not a substitute for good old fashioned clean code. We're not trying to exempt ourselves from thinking about our code and putting effort into its quality. Instead, we're trying to set ourselves up to fall into the pit of success by making bad decisions hard, and good ones easy.
But how exactly does Micro Frontend make “bad decisions hard”? In my opinion, without strong organization culture, with delivery pressure in place, with freedom which makes workarounds and other stupid things simpler, such freedom leads to chaos and it only makes things worse! New systems mean new problems [Systemantics]. Instead of dealing with one set of issues, we now need to deal with multiple sets of issues (more about it below).
Just as with microservices, independent deployability of [M]icro [F]rontends is key. This reduces the scope of any given deployment, which in turn reduces the associated risk. Regardless of how or where your frontend code is hosted, each [M]icro [F]rontend should have its own continuous delivery pipeline, which builds, tests and deploys it all the way to production.
That’s a step in a good direction. But we must stress the importance of integration and regression testing. Complex systems exhibit unexpected behaviors [Systemantics] & distributed systems are complex systems = each part of the system may work fine individually, but once integrated, they may lead to unexpected behaviors. Fully isolated sub-projects later “composed into a greater whole”? Situation like that almost never happens. Almost always these parts will affect each other more or less.
As a higher-order benefit of decoupling both our codebases and our release cycles, we get a long way towards having fully independent teams, who can own a section of a product from ideation through to production and beyond. Teams can have full ownership of everything they need to deliver value to customers, which enables them to move quickly and effectively. For this to work, our teams need to be formed around vertical slices of business functionality, rather than around technical capabilities.
Who wouldn’t like to work in a fully independent team, right? The sense of ownership can really be powerful, no doubts here. But, it’s completely possible to own something and at the same time not to be isolated. That’s a myth anyway, there’s always some sort of dependency. Isolation is almost never good. Cooperation is the key. And yes, I recognize it’s much harder to build the culture that way, it’s much simpler to divide projects and teams. But simpler or faster doesn’t mean better.
As frontend codebases continue to get more complex over the years, we see a growing need for more scalable architectures.
Cure the disease, not the symptoms! We talk way too much about how to deal with complexity, rather than talking about how to achieve simplicity. Simplicity is the key, not how easy it is to manage complexity.
As a more distributed architecture, [M]icro [F]rontends will inevitably lead to having more stuff to manage - more repositories, more tools, more build/deploy pipelines, more servers, more domains, etc. So before adopting such an architecture there are a few questions you should consider:
- Do you have enough automation in place to feasibly provision and manage the additional required infrastructure?
- Will your frontend development, testing, and release processes scale to many applications?
- Are you comfortable with decisions around tooling and development practices becoming more decentralized and less controllable?
- How will you ensure a minimum level of quality, consistency, or governance across your many independent frontend codebases?
We could probably fill another entire article discussing these topics. The main point we wish to make is that when you choose [M]icro [F]rontends, by definition you are opting to create many small things rather than one large thing. You should consider whether you have the technical and organizational maturity required to adopt such an approach without creating chaos.
Finally! I checked - the article has 55,154 characters, 8,486 words. The section “downsides” has only 6,193 characters, 988 words. Only 11%! And of course it’s placed at the very bottom. Meanwhile such questions as above are crucial! Micro Frontend requires technical and organizational maturity!
My personal perception is that many organizations choose Micro Frontend architecture by mistake. The teams tend to be as much autonomous and independent as possible, and so they isolate their parts of projects, of source code, as much as possible as well. Don’t mix causes with effects! It’s The Conway’s Law which states:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure. ~ Wikipedia
That way, at some point of time the projects have some similarities with Micro Frontend, and that’s only one step before someone says - hey, let’s do Micro Frontend! That’s a really poor implication. Please, first ponder the questions - is the project supposed to be so complex? Or have you folks just made it so complex? And, is there seriously no way to make it simpler, to reduce its complexity?