In this article we are going to explore a simple Micro Frontend example project and see how teams can structure, build, deploy, and integrate product features into an existing monolithic application. After reading this article you will understand the "why" and the "how" of Micro Frontends.
Micro Frontends enable teams to work more efficiently by allowing them to independently build and deploy mini full stack applications. They have a clean separation of concerns and the development teams have ownership of the end-to-end user experience. Here's the code: github.com/heyMP/practice-question-service
The application that we are exploring is called Practice Question Service. In this scenario, our team is supporting multiple educational course websites. The goal of this project is to enable students to create practice questions as they move through the course material that they will then be able use as review material when preparing for exams.
A user story for this feature might be presented to the development team as: "As a student that is reading through course material, I read a piece of key information that I would like store for review, I'm able to easily create a practice question that contains the following information: 'question', 'answer', and 'notes'."
Some typical development challenges arise in this scenario if our teams are working within a monolithic application:
Limited deployments: Monoliths, not always, but typically opt for long sprints between deployments. This is to reduce risk of new features introducing regressions to its large feature set.
Feature collision: Every feature being in one bucket means that sometimes a feature may introduce regressions to other functionality (you'd be surprised how often this happens). Which is why core teams try to the limit the amount of new features being introduced concurrently.
Limited technology stack: With monoliths, you have to work with the tools you are provided. Integrating new technologies within the monolith is often a significant lift. Also, introducing new technology to the monolith means more responsibility for the team dedicated to ensuring 100% uptime.
Ownership: When you have large teams supporting a monolith many times the responsibility for a feature can bounce from one developer to another. This sounds good on the surface but often leads to developers having maintaining product features that they aren't completely familiar with.
The Micro Frontend model aims to solve the problems listed above by enabling many small, cross-functional teams to build and deploy product features independent of the core monolithic. They have their own technology stack, their own deployment pipeline, and a dedicated team to support the core mission of the product feature.
source: Michael Geers https://micro-frontends.org/
Now let's take a look at our example Micro Frontend!
Our project is made of two discrete pieces; backend and frontend.
The frontend is responsible for any user experience that we need to provide to our customers and product administrators.
The backend is a purely headless service. This is the API responsible for receiving requests from our frontend components. Note: it can also be responsible for communicating with other backend services.
For our practice question service, those two pieces are in the following directories.
This directory will contain one or many components that are meant to serve as the integration point between our course website and our product feature (practice questions). Any user experience (UX) that you need to provide to your users will be composed and delivered in these components. In our case, these are a collection of web components. In your case they can be React, Angular, Vue, etc. Whatever you pick, just make sure that they integrate seamlessly with not only your monolithic application but with other Micro Frontends (which is why we choose web components).
For our backend, we are using Hasura. Hasura is an absolutely fantastic microservice framework that enables us to easily build a robust API for our frontends. Again, the technology stack is up to you; whatever best suits your teams needs. Just make sure that it is API first and easily deployable. All configuration changes to your backend should be described in code so they can be deployed simultaneously with the frontend.
When our practice question components are placed in our monolith, they should be able to communicate with our backend out of the box. They will immediately ping the backend service to ensure it's operational and begin fetching any data required to set itself up. The frontend components also understand how to create data. In our case, the component understands how to take question, answer, and notes text fields and send them to our backend service for storing.
The components also know how to handle errors coming back from our backend. If the backend responds to a new submission with an error, the component should understand exactly what to do with the error. In our case, showing a dialog message saying there was an issue creating their question and prompting the user to try again.
Deployments is something that will vary greatly from depending on what technology stack you have chosen for your Micro Frontend and governance around how new features are deployment to your monoliths. I could not due the topic justice in this article so I will leave that for another day. The good news is that Micro Frontends are by nature very flexible so they can fit into whatever deployment strategy your team decides.
In the case of Practice Question Service it would look something like this:
Our backend Hasura service will be deployed to Hasura.io managed cloud service. Our frontend components will be published to npmjs.org. And unpkg.com will automatically publish our components to a CDN (Content Delivery Network).
The integration point between our Practice Question Service and our existing application could not be more easy. Our application is responsible for three things. Registering the components, specifying the location of where the components should be rendered, and setting necessary environment variables.
For the purposes of this demo, we will be adding the Practice Question Service to a demo page in our repo.
First, we register our practice question component with our site by simply importing it via a script tag.
Now that our component has been registered, we need to specify where it should render in our application. Web components allow us to do this easily.
Now that the component is registered and placed on our application, we can see that it's working but is not yet communicating with our backend.
The only additional thing that our application is responsible for providing the component is the location the actively available backend. This will be in the form of a url. This handoff of environment variables between the application and component is the equivalent to what happens on the server. Servers are responsible for setting runtime environment variables to applications. This is precisely what we are doing here with the endpoint variable.
And that's it! We now have successfully integrated our Micro Frontend. 🎉
This article doesn't even begin to scratch the surface of this topic but I hope it illuminates the basic principles of Micro Frontends. Micro Frontends open up a world of possibilities to teams that have struggled to release product features quickly and maintainably. This modal provides a clear separation of concerns. It enables teams to have increased ownership and independence without compromising the stability of existing applications. As a long maintainer of monolithic applications I truly believe Micro Frontends are the future of building web applications and that makes me excited 😎.
The code for this demo can be found on my Github repo: https://github.com/heyMP/practice-question-service
Please give me a shoutout or a share if you enjoyed this article. https://twitter.com/hey__MP
Cover image credit: Sey Yeaple