Not sure where micro-frontends would fit in your current architecture? Luca Mezzalira, author of “Building Micro-Frontends,” speaks with Lucas Dohmen, a senior consultant from INNOQ, to share what problems you can solve with micro-frontends and where they can fit within your distributed systems.
Luca Mezzalira: All right. Thank you for having me.
Lucas Dohmen: My name is Lucas Dohmen. I'm a senior consultant from INNOQ, and I'm also very interested in frontends and how to build good architectures for web applications, especially big ones. Luca, maybe you can introduce yourself.
Luca Mezzalira: Sure. My name is Luca Mezzalira. I'm Italian but based in London. I'm a principal solution architect in AWS and in the last seven years, I have explored the micro-frontends topic quite extensively, not only writing a book but also building multiple applications and helping customers to implement these architecture patterns across different industries, seeing different challenges and figuring out how to overcome them. So it has been a very interesting journey so far. So I hope that will continue.
What problems do micro-frontends solve?
Lucas Dohmen: Awesome. Micro-frontends is already a word where different people have different ideas of what it means. But before we get into that, I want to start with your motivation. Why are you looking into this topic? What are the problems that you've seen that led you to explore micro-frontends?
Luca Mezzalira: Seven years ago, I was working for a company called DAZN, which is an OTT streaming platform. Imagine Netflix for sport. Our focus was mainly live content. It was available in multiple countries that have different needs. We started to grow significantly moving from tens to hundreds of people in the tech department. The challenge we had is that we don't only develop content for web, but also for living room devices, so set-top boxes, consoles, smart TVs. And therefore, we need a variety of teams that could handle all the challenges. And moreover, the team was distributed.
On frontend, I have worked in the past on several projects that require tens, if not even hundreds of people working together for delivering a project. But when you have a monolithic codebase, sometimes you have some challenges that are mainly due to the fact that there are some decisions that are pertinent and made at some point in time, but then reverting or changing those decisions across the entire code base is a challenge. And instead, what we were seeing on the back end is that there was distributed architecture that allowed different people to have certain modularity and flexibility that we didn't have on the frontend. So back in the days, I was asking myself, "Can we figure out a way to have the same flexibility of microservices, for instance, on the frontend?"
Lucas Dohmen: I think one of the things that's the most important part of both microservices and micro-frontends is the idea of independent deployments. So the idea is that a team can decide for themselves, that they can deploy something without the other teams needing to do something about it. Maybe you can talk a bit about that topic as well because I think it's very important for our conversation today.
Luca Mezzalira: Sure. One of the characteristics of a distributed system, like if we think about microservices, as well as micro-frontends, is exactly what you described. So the fact that our independent artifacts, and that is not only helpful from a technology perspective, but also from an organizational perspective. One thing that I have noticed in the past is that very often, people forget that architecture is tightly linked with the organization structure. And that is something we cannot forget.
Conway's Law, for instance, states that we usually design our architecture, or our system based on how our company is structured. That is something that was stated in the '70s and is still very actual, in my opinion, and we need to take that into account. The fact that we want to have a distributed system, means that we need to reduce the external dependencies for the team. Because otherwise, it's creating more overhead in coordinating the effort. That is not only for independent deployments, but it's also for sharing libraries and many other things that we used to do when we deal with certain types of projects.
Now, specifically on independent deployments, I think is quite key that we are trying to use best practices that we have learned in the microservices world and apply, if possible, on the frontend for defining some boundaries around the micro-frontend input and output, for instance, and then having the possibility to independently deploy at our own pace without the need of massive coordination. That doesn't mean it is always possible. It means that for the vast majority of the time, a team’s day-to-day is that I'm independent, I can make my decision, I can go ahead and deploy multiple times per day or every day, whatever is the cadence that they prefer.
Whether there are certain situations, for instance, when there are features that are across multiple domains of our application, or we have a massive change like a design system that is changing drastically, we need to do some coordination across teams. That is inevitable and is going to happen. But if we can reduce it to less than 5 or 10 times per year, then we will have a big success. Because every team is independent for a vast majority of the year, and then will be able to take their own decision and move forward with what really matters at the end for a company. So generating value for the users. Because we are often forgetting that we are here not only to write amazing code, but also for generating value for our customers. And that, for me, is the key thing that we need to focus on, especially nowadays where applications are becoming more complex and users are requiring, let's say, specific features and richer features if you want. And in this case, I think modularizing our architecture is a key characteristic for any application for the future.
Where do distributed systems fit in?
Lucas Dohmen: One thing that you also outlined in your book is that, of course, splitting up your system into a lot of different systems comes at a cost. It's not free to split up your system. You need to integrate it, and we will talk about that at length in this conversation. So you have to do a lot of decisions. Where do you come down on the decision on when to do the split? Do you think you should always start with a distributed system like a micro-frontend microservices system? Or do you think there is a good reason to start with a monolith and split it up later? Where do you think you come down on that?
Luca Mezzalira: Yeah, let's start stating that I don't believe distributed systems are a silver bullet at all. I would say that that is more a way to solve an organizational challenge and not only a technical challenge. Probably mainly an organizational challenge than a technical one. I think there is a lot of value nowadays working with monolithic architectures, or a modular monolith even better, as was described several times by Sam Newman in one of the books that he wrote, "Building Microservices" and "Monolith to Microservices."
I think in general, the idea is you need to really think about your context and find which is the right architecture pattern for what you need to achieve. Sometimes for a startup, having a quick turnaround makes way more sense than starting with microservices or micro-frontends. Because you don't even know if your product will reach prime time. And therefore, it is very, very important that when we think about the architecture part and implement it, we need to think about our priorities. And often for startups is validating their assumption or idea. How many customers are interested in that? And then set up the code and the architecture in a way that the modularity characteristics that we discussed before could be leveraged at scale.
In reality, if we think about architecture characteristics, I think modularity is one topic that we talked about for several years. And I created the mental model in my head that you can reach a different level, you can have the code level, you can have the infrastructure level, you can have at the architectural level and organization level. And those three things don't have to be achieved in the first iteration. You can start with a monolithic architecture with a modular code base, and slowly but steadily move into more granular modularity on the infrastructure. And then slowly but steadily you move towards the architecture that I believe is the last phase where you have modularity on the code, on the infrastructure, on the architecture for the organization based on the assumption that we design our architecture based on organizational structure?
If that is true, it means that you can achieve some of the benefits that you can have with distributed systems also with a monolithic codebase, or whether require more discipline or require certain coordination that you might not have to think about when you go further about the abstraction that you are talking about. I think also with a monolithic codebase, you can achieve some benefit of modularity at the codebase level, and then that will be your foundation for moving towards.
Splitting your application: horizontal vs vertical split
Lucas Dohmen: Very nice. After talking about the motivation, I think we should shift our focus a bit to micro-frontends and away from microservices. In your book, you wrote that there are basically two big categories of doing micro-frontends. And this also will lead us to what exactly that means. I prepared this visualization, which I stole from your book, which shows the horizontal split versus the vertical split, right? Can you explain to us how you can split your application into either horizontal or vertical splits, and what are the benefits of those two approaches?
Luca Mezzalira: Sure. When I started my journey in this world of micro-frontends, obviously, I struggled to find some content available online. And there weren't many companies doing that. So I had to figure out and create some mental models that would help me and other developers working with me to visualize what we were talking about. And I created what I call the decision's framework in 2019. Basically, one of the decisions is the one that you mentioned. So the vertical versus horizontal split. And that is the first decision. So when you are approaching micro-frontends, you need to understand how granular you want to go. That doesn't mean you cannot mix and match both, you can definitely mix and match both. But there are certain situations where one makes more sense than the other one.
A horizontal split is when you have multiple teams working together inside the same view. So if you reach a homepage of a website and you realize that there are multiple teams working on that, because your organization is quite large, and you have multiple domains that the homepage is covering, or you have, by the type of system, a certain level of granularity and reusability on micro-frontends, that is definitely an architecture that I encourage. A classic example, for instance, think about an observability dashboard where you have multiple elements that can, in a homepage, correspond to the throughputs that you have, or the error rates and other things. So those are multiple domains that are contributing to providing a final view. And those domains, obviously, are very likely to be handled by different teams. So in order to aggregate that, you can use a horizontal split where you collect different metrics to provide a view to the final user.
On the other side, we have a vertical split, where instead, a team is responsible for one view or multiple views. Depends on the type of application that you have. So, for instance, if we continue with the example of the observability dashboard, maybe you go to the homepage and select error rates as a metric that you want to deep dive and understand better how to fix. So at that level there, you can open it and you see that it’s owned by the team responsible for the error rates that goes more in-depth about the visualization, the charts that you want to display, and maybe you can do some queries, and search, and other things. So in that case, you can have a mixed approach where you have a team that is responsible for the vertical split of the application and the same team responsible for the smaller view or the snapshot of the view of the error rate that contributes to the homepage. So as you can see, you can have both.
Obviously, those approaches have different pros and cons. In horizontal split, I have seen more and more people that are investing in tooling for providing capabilities for the team that is, let's say, rendering just a portion of the view, some traction to understand if the micro-frontend that they develop is working. And also there are some challenges around the organizational structure. Because imagine that you're responsible for just one micro-frontend in the view that is composed of, I don't know, five micro-frontends. Let's assume this example. How do you ensure that your micro-frontend is working? I have seen companies that are decoupling the teams and having a Q&A session that is owned by the Q&A team for making sure that the application is working as a whole.
And on the other side, I've seen teams that instead are creating tools for making sure that the application or the micro-frontend is working in conjunction with other micro-frontends. And therefore, the investment around ephemeral environments, where in that case, basically, you spin up a snapshot of the system, maybe retrieving other micro-frontends from a more stable version, like staging environment, for instance, and your micro-frontend is working alongside. But as you can see, there are more considerations to take into account when we work in a horizontal split.
Single-page app vs Rich page app
Lucas Dohmen: But I think there's still a lot of movement there, especially with things like hot wire and technologies like that, where the line is not so easy to draw between server-side rendering and single-page applications. But I think we have a rough picture of what we mean. It's a very client-driven application, probably with routing on the client-side and not on the edge or on the server.
Luca Mezzalira: It could be either way. So the interesting part of the vertical split, for instance, if we want to go ahead with that topic, is that usually the routing part could happen on the client-side or it could happen at the edge side. I have seen it working both ways. If I think architecturally speaking, having it at the edge side provides a nice decoupling between the container of these micro-frontends, usually, it's called application shell, and the routing mechanism. If it is on the client-side, it might be non-trivial. Because there are a few things that you need to take into account. In the end, you are consuming, the vast majority of time, an endpoint for retrieving the catalog or micro-frontends that are available, and then you use some logic that you add in your code for the application shell.
The challenge you have if you do on the client-side, is you're not paying too much attention to decoupling in a nice way, this catalog of elements with the mechanism that does the routing is the fact that you need to deploy the application shell alongside some micro-frontends every time. That I have seen as an anti-pattern because basically, you're creating a coupling between the container of your micro-frontends and the micro-frontends itself that represent a piece of the domain. If you do it on the edge side instead or server-side, depends if you want to go up to the origin, the nice thing is that when there is a request from the client, the logic running on the server is just retrieving the right artifacts. And that opens up two possible solutions like kind of releases, blue-green deployment, or even strangler pattern, if you want, for migrating an existing legacy application or monolithic codebase towards a new micro-frontend.