This brief post is dedicated to collect some impressions and basic ideas about Micro-Frontends (MFE). There are some books, articles and materials out there. But nevertheless, there are always some thoughts about some aspects that are not well described or considered. We'll focus here on these topics:
- Types of issues that MFEs can help to address
- Impact on the organization of teams
- Delivery Pipelines
- Quality and Compatibility
- Communication of Micro-Frontends
Types of issues that Micro-Frontends can help to address
I think this is a good list:
My API Consumer, UI or Webapp is a monolith! Perhaps the backend guys built a MSA (Micro-Services Architecture) but in the Frontend we still work in the old monolithic way. This means:
- Sub-teams dedicated to develop modules with specific views/sections of the app.
- Big app gathering modules
- Even the smaller change implies to deploy everything, the whole app.
- Releases are slower and slower and test phases are endless.
- The integration of modules is more difficult and complex every day.
So, first thought: If I use independent apps that can collaborate somehow and or composing some unified meaningful set of utilities (an "application") for the final user it could be a good idea.
In fact, the idea of decoupling the development and delivery of multiple components to be gathered in a common runtime (the web browser) is really appealing. Why? Exactly because the same reasons that a MSA is a good idea:
- Software built can be broken down into multiple component services, so that each of these components can be deployed and then redeployed independently without compromising the integrity of an application. That means that this architecture gives developers the freedom to independently develop and deploy components.
- Better fault isolation; if one fails, the others will continue to work.
- Code for different services can be written in different languages.
- Easy integration and automatic deployment.
- This architecture enables continuous delivery.
- Easy to understand since they represent a small piece of functionality, and easy to modify for developers, thus they can help a new team member become productive quickly.
- The code is organized around business capabilities.
- Scalability and re-usability, as well as efficiency.
Impact on the organization of teams
We can agree this approach increases the autonomy of individual development teams within an organization, as ideas can be implemented and deployed without having to coordinate with a wider IT delivery function.
I can arrange multiple teams/squads/sub-teams to focus on a specific section of the application from a functional and visual point of view. It does not matter what JavaScript framework is used (React, Angular, etc). The important stuff here is:
- The components have a uniform Look & feel and Style.
- They do not contain duplicate functionalities.
- All together compose a bigger entity (the application) even though it is possible that only some components are needed.
- They are compatible. This means, they can eventually communicate to each other without breaking.
- All components follow the same rules regarding Quality (Uniform Quality) and Compatibility regarding the rest of Micro-Frontends so that the resulting set of functionalities (the application) cannot be considered as "broken".
In this case, the teams/squads share some common elements in the form of libraries and modules (styling, security, etc) but not the runtime. Each components is thought to be eventually independent. Business Analysis, requirements, internal business logic, etc is autonomous. Of course the decomposition can be done AFTER Business Analysis, for instance. It is just a matter of adapting to your practices and peculiarities.
In any case the team/squad can have a leader that controls the evolution of the Micro-Frontend as a whole as well as he/she supervises the relationships with teh rest of Micro-Frontends.
As MSA before, MFEs provides a higher level of flexibility in exchange of accepting more complexity. This is the trade-off!
Delivery Pipelines
The Delivery Pipeline is one of the main concerns. Hoe are they affected by the MFE approach? Well, it is obvious that we need a separate pipeline for each MFE. It is also needed a different separate runtime (e.g. web server) completely isolated and independent of each other.
Below diagram tries to show the layout of a possible project. A web app has been decomposed into 4 MFEs. One of them is common because it contains the header with common functionalities (user account, preferences, warnings, notifications). This is a common case in web applications architecture. Other options fit here but we can consider this simple example for now.
First, there are 4 development squads adapted to the expected requirements and importance of the specific MFE.
The main conclusions are related to boundaries (it is what MFEs is actually about):
- The delivery lifecycle of each MFE is completely isolated.
- The logical scope is also a boundary. Each team works with a different sub-set of business logic and implements different functionalities.
Quality and Compatibility
As we can see in above diagram, there are two main "gates" or check points in the delivery pipeline, Quality and Compatibility Gates.
The release of a MFE has to follow two simple rules:
- The Quality Gate. It has to meet a set of commonly applied set of Quality criteria (SCA-based).
- The Compatibility Gate.
The MFE version has to be in the compatible range regarding the rest of
the MFEs in the app. The Delivery Pipeline has to be able to stop the
build if the version range is not the expected one and report about this
circumstance. So, the existence of the Compatibility Matrix is
mandatory (how it is implemented is out of the scope of this post).
Communication of Micro-Frontends
Following the simple example mentioned before, above diagram shows that eventually the MFEs have to be able to send messages to each other.
Well, this is something to avoid if you ask, from a personal point of view. I do not see why the MFEs have to designed to be coupled. Possible reasons?
- The state of an MFE depends upon the state of other MFE.
- The data displayed by an MFE has to changes as the result of an action in another MFE.
- An MFE containing common functionalities can change the state of any other MFE.
From a personal point of view I think this pattern of coupled states is completely avoidable.
First, the state of the MFEs have to be completely autonomous. The shape, display of data etc should be self-conttained obeying only to actions in the MFE.
Second, a change in data in another MFE that supposes that our MFE has to change the displayed data to be consistent should be done in a reactive way, pushing the change from the server (we assume the change in the other MFE implied a change in the backend). It is important here to think of server-push techniques (e.g. HTML5 Web Sockets) or even better, use HTTP/2 and gRPC.
Third, changes in common functionalities should not affect to the state of MFEs. They should provide only capabilities of visualization and owned features (e.g. notifications, user account management, etc).
That was all! I recommend you to read articles and materials about the topic and look for new approaches that can solve your issues.
Cheers!