Since some time ago, there has been growing criticism towards Microfrontends (MFEs
) with the assertion that "if Microfrontends are needed, it's due to organizational problems."
I think this statement holds some truth as it is indeed related to organizational challenges. However, in these situations, the code must be adapted to address these issues effectively.
In this lecture, I aim to guide you through:
- When Microfrontends are neccessary
- The problems Microfrontends solve
- Unmask the myth that Microfrontends are harmful
- The challenges that accompany Microfrontends
☝️ Important note |
---|
This lecture will focus more on concepts and ideas rather than specific technical solutions. |
☝️ Important note |
---|
This is mainly my opinion based on my experience and research. |
- From a Small Project to a Behemoth
- MFEs: A Potential Solution
- Emerging Challenges
- Wrapping it up
- Interesting Links
From a Small Project to a Behemoth
When a project begins, it is typically small, manageable, and easy to collaborate.
In the case of a small Single Page Application (SPA)
, a modulith architecture
often provides an efficient and quick solution for web needs.
The team, around 5-10 people, are able to work together, coordinate, have nice DX and develop and maintain features without any problem.
Let's say, the project is a huge seller, it's the golden goose of the company, attracting significant attention.
The First Challenge: Scaling the Team
As the company invests more in the project, seeking to enhance its speed, power, and scope, they increase the team's size. Soon, 20 to 30 people are working on it.
Collaboration becomes more challenging, leading to the team dividing into smaller groups of about 10 people, each focusing on different modules or domains of the SPA. Despite this, it remains a monorepo SPA
.
This growth introduces bureaucratic hurdles. Every new feature or library addition impacting the entire ecosystem requires alignment with all teams.
The Second Challenge: Budget Constraints
Over time, some sections of the website gain more popularity or importance, leading to a reallocation of resources and reshuffling of teams. This results in uneven development capabilities across different groups.
Time keeps passing and your favorite framework (Angular❤️) has released a new shining version that brings a lot of interesting features to the table. Some of the teams are eager to upgrade inmediately, because the new control flow syntax it's amazing, but, others lack the resources required to migrate in that moment and can not afford the breaking changes and adapt their code.
The Third Challenge: Framework Limitations
When the product continues to be successful, the company will want to hire more people, invest more resources and make it even bigger, but they find a shocking surprise:
❗They cannot find more Angular developers❗. The company already contains a lot of them, but there are not enough developers in the market, and even less with strong skills in Angular.
Hiring developers from other frameworks and training them poses a significant financial burden.
The Current State of the Project
Now the project is in a tight spot, although the client that uses the application does not feel any of these problems, thanks to modulith, the efficiency of the website keeps feeling contingent, but, our DX is getting worse and worse.
The codebase has grown enormous, leading to long build and deploy times, and local development becoming increasingly painful.
MFEs: A Potential Solution
Defining Roles
After all the problems we have discussed, let's now introduce our hero of the day. Microfrontends.
Let's apply MFEs
to the SPA
we have been talking about. The first step is to designate the Shell
and the others MFEs
.
The Shell
will handle common functionalities across the application, including authentication, relieving the MFEs
of these concerns.
Each team, previously working on a specific module or section, now oversees an individual MFE
.
This leads to splitting our SPA monorepo
into multiple repositories, one for the Shell
and others for each MFE
. Each now operates as a separate application with its own deployment and build processes.
Module Federation
Now we can integrate Webpack Module Federation, for example with the library of AngularArchitects.io
☝️ Remember |
---|
As said, this lecture focuses more on the idea and concepts. For a technical solution, I recommend reading the series of post of AngularArchitects.io |
At this stage, we have already solved:
- Team Scalability: Teams can work independently, reducing conflict risks.
- Framework Flexibility: Adoption of different frameworks (e.g., React) becomes feasible within teams.
But what about budget constraints?
Web Components
Web components allows us to encapsulate even further our Microfrontends, solving the existing problems with pure MFEs
about conflicts in namespace, css and dependencies.
This allows for different Angular versions within the Shell
and various MFEs
.
For example, the Shell
might run Angular 17
, while a budget-constrained MFE
continues on Angular 15
, yet they still function cohesively and they can communicate with each other through Web Component
using Inputs
and Outputs
(Outputs transformed to CustomEvent
by itself) or a whole own implementation for communication purposes based on custom events
.
☝️ Important note |
---|
Module federations allows using shared services for sharing state but when using different versions of the framework this is not longer possible, because they have separated Angular Dependency Injection trees with different root scopes. |
Emerging Challenges
Despite its advantages, this new ecosystem introduces its own set of challenges.
Normalization
Now we have so many separate artifacts (Shell and MFEs). Before in our SPA
it was as easy as using a shared module
, with this new context we cannot do that.
In order to still have normalization of UI components, styles and etc, we would need some libraries. We can develop libraries for normalization to be used in every single artifact.
❗ Important! |
---|
I' am using Shared Modules as an example but they are not a good solution for sharing code. |
Bundle?
Now our bundles are smaller, but we have a new problem. The bundle now depends on versioning, and Web Components can increase it significantly. If we have a happy path and every single artifact is Angular 17
, when the client enters the website, it will load the Shell
and the bundles for Angular 17
, the users navigates and everytime it loads a MFEs
, if using Angular 17
, they will just reuse the already download bundle.
Now let's see another reality, where we have the Shell
and four MFEs
in Angular 17
, another two MFEs
in Angular 16
, and three in Angular 15
. What will happen when the user keeps navigating through those MFEs
is that it will download the bundles for each Angular
, ** increasing the usage of resources in the client.**
☝️ Important note |
---|
I have used Angular versioning as an example, but this affects to every single dependency, could be the framework, or any library. |
Contractual Coordination
Another thing to keep in mind are the contracts. Now the Shell
and MFEs
will communicate mainly through Inputs and Outputs, and those are separated in the Shell
and MFE
, so they have to be very well-defined. This could be helped with shared libraries.
Routing Considerations
The browser of our client has only one url sadly, so this means that it should always be delineated as what is being shown on the screen. If we go to a scenario where we have two MFEs
loaded at the same time, and both of them have routing, they will navigate internally but will also modify and replace the url, so now it could be different from what is being shown in the other MFE
.
❗ Important! |
---|
Only the Shell and maximum one MFE should have access to the routing |
☝️ But soon... |
---|
angular-architects is currently developing a library that allows multiple routers, the first stable version should be in the first quarter of 2024 |
Wrapping it up
In conclusion, MFEs
can be an excellent solution to solve a vast amount of issues that are not necessarily because of the lack of organization or planning, but because of the nature of the product itself.
Although, there are always new challenges to be solved when working in this ecosystem. In my opinion, for big projects, this solution is mandatory and new challenges can be solved with robust and thoughtful architecture.
I hope you have enjoyed reading this lecture (my very first article ^^) and that it was useful for you, for any question you might have, you can contact me in any of my linked social media. Thank you!
Also especial thanks to MikeZks for helping me polishing the article.
Top comments (0)