It is crucial to understand the MFE architecture before considering its adoption in our business.
Understanding the advantages, disadvantages, and risks associated with MFEs will allow us to make well-informed decisions. Additionally, understanding the specific context in which the architecture is applied, guided by the famous word ‘it depends,’ is essential since the adoption of MFEs, like any other architecture, must be tailored to the particular circumstances of each business.
In this article, we will break down the key concepts of MFE.
Some Concepts
Before diving into details, let's define a common language regarding key elements in MFEs:
Terminology
Components: Code blocks that offer specific functionalities, generally independent of the business context.
Design System: A dynamic framework that unifies visual style and facilitates collaboration between teams.
Web Applications: Digital platforms composed of components that together fulfils a function or provide a business service.
Micro-frontends (MFE): Allows teams to operate independently by dividing the web application into modular business units, each with its own development and autonomous deployment.
When to Use MFE?
The decision to adopt an MFE architecture must be strategic and based on the company's structure and needs, not simply a response to current trends.
Some reasons that could justify this choice include:
Decoupling and Autonomous Business Units: If the goal is to promote autonomy and decoupling in business units, an MFE architecture could significantly optimize testing, pipelines, and deployment times, thus improving the CI/CD process.
Scalability: If rapid growth in functionalities or user traffic is anticipated, MFE allows each business unit to scale independently. Every business is a universe full of challenges, and the situations mentioned above may not apply to all circumstances. However, they can serve as a starting point for making a decision.
Framework Migration: Whether to upgrade to a new version (such as from Vue2 to Vue3) or to switch to an entirely different framework (from Angular to Vue or React).
Company Acquisition: If a company using React acquires another that uses Vue, and both need to integrate without migrating all their applications.
Microfrontends (MFE)
There are various authors who discuss the topic of Microfrontends.
In particular, I have liked how Luca Mezzalira addresses the topic in his book Building Micro-Frontends and some other resources in blogs and YouTube channels.
Let's take a look at some of these concepts that together would form our MFE working framework.
1. Define how we will distribute our MFEs.
When distributing our MFE, we can identify two main approaches:
Horizontal: In this approach, we delegate sections of our application to different teams that work on the same view. This involves a single view with multiple responsibilities.
⭐ Vertical: Here, we divide our applications by business domains, which are generally managed by a single team. Each business unit has its own view with one team responsible for it.
As with any context, the choice between these approaches will depend on specific needs and who implements them. However, the vertical option is recommended, as it simplifies the team's work.
The choice between these two architectures presents different challenges, which are described in more detail in this article: identify micro-frontends.
Below, I'll share some lessons learned.
2. Define where we will perform the composition and routing of our MFEs.
As our application scales, the need for a container application, often referred to as a Shell app, becomes evident. This container manages crucial tasks such as routing, loading components, handling error pages, and implementing authentication logic and permissions. By centralizing these responsibilities, the Shell app effectively orchestrates the integration of Micro Frontends (MFEs) and ensures a cohesive user experience.
Some frameworks that allow for this include Single SPA, Module-federation (Webpack — Vite ), Client side transclusion, Piral among others otros
Client-Side Composition
Router: The client | Composer: The client.
In this option, we will have a Single Page Application (SPA) called a shell that will be responsible for mounting and unmounting views based on the URL state.
Advantages: It facilitates understanding and controlling the routing and composition of views.
Disadvantages: as all the resources must be downloaded by our clients, It requires careful resource management to avoid negative impacts on performance and efficiency.
Recommendation: Measure the implemented changes and optimize the use of shared resources to ensure good performance.
Routing in the Edge
The edge can be used to route our clients to the corresponding view, and at the same time, we could decide to compose or modify the body of our response as needed.
Advantages: Routing at the edge will allow us to make faster decisions, and it becomes very useful during migration phases.
Disadvantages: It requires a bit more cloud knowledge, and changes may take a little longer to be reflected.
Recommendation: Using this strategy in combination with client-side composition can facilitate the migration of monolithic applications.
You can see more about this in this repository
Server-Side Composition
In this scenario, the composition is done on the server, while routing can be performed either on the server or at the edge.
Although I haven't had the opportunity to implement server-side MFE, in Lucas' post, some options like Ara Framework, Open Components, Piral, SPA or Tailor.js are mentioned. Here, Lucas recommends using client-side composition for vertical composition and any of the three options for horizontal composition.
Advantages: Faster initial load (FCP), improved SEO.
Disadvantages: Higher cognitive load, requires server resources, client-side caching cannot be leveraged, slower TTFB.
Recommendation: Make this decision carefully, as it can significantly complicate development.
3. Communication
Keep this in mind : "low coupling high cohesion"
As our system evolves and we begin distributing it, the risk of coupled distributed systems increases. It’s crucial to focus on our original goals: domain and team independence.
To achieve this:
Minimize Communication Between Domains: Reduce interactions between different views, domains, and teams. Each part of the system should be owned by a single team, avoiding shared ownership of components, libraries, or code to minimize side effects.
Maintain Single Team Ownership: While teams can use shared services at runtime, each service, application, or subsystem should be managed by only one team (see Team Topologies, Chapter 3).
Practical Tips:
Limit MFE Communication: Avoid interactions between micro-frontends reducing the creation of stateful systems.
Version Your Components: If needed share business components between MFEs at build time while ensuring they are versioned and maintained by specific teams.
Use Alternative Communication Methods: When necessary, use events, URL parameters, or local storage for inter-domain communication.
By keeping MFE communication minimal, you’ll simplify your system, enhance team independence, and better align with business domains.
4. Conclusion.
We have explored various aspects of Microfrontends (MFE), from the decision to adopt this architecture to the different forms of distribution and communication between MFEs.
Each approach has its own advantages, disadvantages, challenges, and the choice will largely depend on the specific context of your business and your technical needs.
However, this is just the beginning. There are many other topics that deserve detailed discussion, such as CI/CD, team management and leadership, metrics, deployments, and contracts, as well as practical examples of using MFEs both on the client side and at the edge.
I invite you to share your thoughts, experiences, and feedback in the comments. Your input can enrich this conversation and help others navigate Microfrontend Architecture.