This is a summarized discussion from the CTO Guilds forum—it has been edited for brevity and clarity as well as anonymized.
Context: We’ve benefited immensely from a microservice driven architecture. Following a roughly domain driven design, we’ve been able to separate concerns, onboard folks efficiently, and build quickly. However, our frontend applications are starting to feel monolithic, and we want our development teams to be vertically integrated in the stack, own their UI pieces, and not step on each other’s toes as our product gets larger & more complex.
Question: Have you implemented micro frontends? It feels aligned with backend microservice architecture, albeit quite a new concept. What’s worked well? What should I watch out for?
Reference material: Micro Frontends by Martin Fowler
Answer 1: Many tradeoffs
In my experience, there are a lot of tradeoffs to implementing micro frontends. Some frameworks (like Django) support this concept natively though - you keep individual objects in “apps” that are all served by the same server, but are logically separated in different module namespaces. If you’re properly managing your python packages/dependencies then that sets you up to do that effectively (keep the apps in other packages and bring them all together for the server).
Some additional questions to ask yourself in the process:
- Are the endpoints truly separate?
- If some core model needs to be modified that many of them depend on, do you need to deploy all of them?
- What happens when only some are updated?
Answer 2: Overall very happy
We’re currently migrating away from a monolithic Ruby on Rails application to a microservices backend architecture with React frontends for the web. Each web page is an independent React application (similar to the micro frontend concept), and from an implementation perspective we maintain a single repository that contains all of the frontend applications as well as shared packages, UI components, and tooling.
We’ve been very happy with this architecture, and our biggest challenge has been a historical “all or nothing” approach where we have needed to rewrite an entire page in React to be able to extract the page from the Rails monolith. We’re very excited about the potential for webpack module federation to allow for a more incremental migration approach.
Answer 3: Page transition performance difficulties
We migrated to a single page app approach a while back. We’re finding that page transition performance is harder to address now. This is especially difficult in our hybrid mobile apps.
Answer 4: Strong endorse—completely modularized from the get-go
We adopted the micro front-end methodology from day 1 and it's been really great for us. Our system has been completely modularized from the get-go and the majority of the front-end libraries have a corresponding backend module that goes hand-in-hand. For example, our User Management module has it's own fully decoupled backend (pluggable as a bootstrapper to our microservices) and also has a corresponding front-end library providing unthemed components like Login, User Profile and Forgot Password to name a few. This allows for any application to simply drop in User Management functionality.
A couple gotchas to be mindful of if you go the SPA route:
- Stay away from compiling front-end projects as npm packages early on as this will inevitably slow the dev team down. However, this approach makes a lot of sense once the codebase is stable and you have multiple teams consuming the package for different projects.
- Use tools like webpack-bundle-analyzer to ensure you are including the minimum set of components required for the module to function. It's easy to get sucked back into a post-compilation monolithic bundle structure after the site has been compiled.
- Leverage prerendered pages + CDN caching wherever you can for improved page load times
Regardless of your approach, try to adopt a CSS convention for styling and theming early on across all front-end libraries as this will allow you to easily leverage these libraries for other applications later on. Finally, try to adhere to separation of concerns within your libraries and keep application specific behavior out of your generic libraries. Any application specific behavior should be built as a plugin to the libraries. For example, redirecting a user to the homepage after signup might make sense for your current application but not for other applications using the library so provide extension points wherever you can to handle these scenarios.
Additional material: Watch former Grubhub CTO Maria Belousova share her journey from Monolithic System to Microservices at our CTO Summit. (video)