How to bring the micro into the frontend

Visma Nmbrs
Nmbrs Tech Blog

--

by Tiago Santos

If you follow this series of articles you know by now that Nmbrs is on the route to breaking its monolithic application. We have dived into the why and the how by going deeper into aspects like structure and data migration, but we still didn’t showcase the changes that our end-users perceive. In this article, we will discuss our path to micro frontends and why they shouldn’t be overlooked in your microservices journey.

One of the goals of going into microservices is to decouple the parts, and one of the outcomes is that you increase the speed of delivery. However, in a product like ours — a full web application — if you only decouple the backend you will find yourself waiting for the big monolith update so that your UI gets updated enabling you to fully release a feature. You’ve gained development speed but at the same time, you have this component throttling you.

Furthermore, the fact that you will still have to interact with the possible mess that is your monolith (when compared with your new services) to develop your frontend is a turnoff for any developer. In the end, it will feel like you are not taking full advantage of going micro.

What do micro frontends look like?

In a very simple way, micro frontends are about bringing the core concepts that exist in the microservices context and applying them to the user-facing aspects of your application.

This means that you don’t only extract the business logic and data storage from the original monolithic application but also bring the UI to the new component, this way you can decouple a full business vertical and simply share between teams what is common to them.

There are multiple ways to achieve micro frontends, there is a nice article by Martin Fowler that even includes some sample code that I recommend reading.

Our take on micro frontends

While our initial approach to frontends for microservices hasn’t aged very well, it was an important step for us.

This first take consisted in splitting the application into multiple SPAs (one per module) which we called Micro-Apps so that each module could have its own deployed app. But after the first iteration, we realized it wouldn’t work for us since it would be difficult to provide seamless switching between micro-apps. It was very clear for the users that a jump between two websites was being done, not a very nice user experience.

To provide the seamless UX we intended, all the UI components needed to co-exist in the same context, our main application. We could only achieve that using the composite UI pattern, thus we started to define widgets and the widget framework.

The Widget Framework

What we call the widget framework is this transversal component that exists in the main application that knows how to load the right widget into the right place on the page. On top of that, it also handles cross-cutting concerns like logging, authentication, and state management. All of these features are built-in and can be used without any extra effort from the developers keeping their focus on the actual feature.

Widgets are small UI components for a specific feature that only interact with their own microservice and that can be displayed anywhere inside the main application.

Developing a widget results in a set of static files that we bundle together using webpack and in a CI/CD fashion distributed via a CDN.

With this architecture, and making use of the CDN’s capabilities with edge node caching, and caching policies we are able to seamlessly update UI components, all it takes is a navigation click and a widget can suddenly have a new feature on it.

As for the distribution of the backend, the distribution of the frontend raises issues of consistency, not on data or tech, but on UX. We had to make an extra effort to implement some generic patterns and some other core components so that even with detached UI the UX looks unified. We achieved that with WebComponents that themselves implement patterns of responsiveness, loading animations, and consistent behaviors. You can read about it here.

In the image, the components outlined in blue are widgets.

What’s next

One of the big points to address is that we still use our monolith as our skeleton app. While this is ok for now, it still doesn’t allow us to decouple some generic logic that exists in the monolith that would be handled by a skeleton app.

We want to make the step to create a new skeleton app from scratch, but the logic that I just mentioned, which includes authentication, for example, needs to be ready for this step, and that brings high impact changes across the product.

Moving forward we want to keep improving our framework, a new skeleton app opens doors to new ways of distributing widgets like module federation and that’s something we would like to look into.

Finally, we want to keep extracting more features into microservices with their own micro frontends. As showcased in this and the previous articles we have a lot of the pain points figured out which enables us to make this long ride a bit smoother.

Tiago Santos, .NET Developer at Nmbrs

About Tiago

I’m a Lisbon-based Software Engineer working at Nmbrs for almost 4 years. During my time at Nmbrs, I have been part of multiple squads and involved in different projects. From the microservice architecture inner workings (my academic background) to, most recently, the UI-facing web components, my goal is to always push tech-forward in a clear and understandable way to everyone after me.

--

--

Visma Nmbrs
Nmbrs Tech Blog

All about getting your HR and Payroll done together!