Noel: Hello and welcome to PodRocket. I'm Noel and joining me today is Ruben Casas. Ruben is a staff engineer at Postman, specializes in micro front ends and large scale front end applications. He is joining us today to cover his recent talk, which is titled Micro-frontends with React Router 6. You gave that at the WeyWeyWeb Conference, is that correct? Ruben Casas: Yeah, that's correct. Noel: Awesome. Awesome. How are you doing, Ruben? Ruben Casas: Yeah, thank you so much for inviting me. I am so excited to talk about one of my favorite topics. So yeah, really excited. Noel: Yeah, yeah. I'm excited to get into this a little bit too. I feel like this is kind of a poignant conversation. It's been on people's minds a little bit lately, so I think this will be a good one. Before we delve in too deep though, can you give us a little bit about yourself, your background, web dev and your time at Postman? Ruben Casas: Yeah, sure. So I'm a staff engineer at Postman and when I was at university I always wondered how are big large web applications built? These applications have millions of users and everything seems so complicated. So that became my passion. I did a master's degree in internet and distributed systems and every time I was like, "Okay," it's actually, it's hard, but it is possible. It's not magic websites work and they have millions of users and it was very quite interesting. Before Postman, I was at American Express, I was one of the maintainers of one of the micro-frontend frameworks and that was huge. We had millions of users, we had about 2000 developers using our framework and he micro-frontends. So now that I move to Postman, I'm trying to do the same. Postman has 22 million users last time I checked. It's huge and we're trying to use micro-frontends to decouple the monolith and something that we're going to talk about later and just do scale. It's usually not the technology than is scaling, it's usually more the people and the organization and solving that problem with coupling. Noel: Yeah, I'm excited to get into that, the organizational need for independent channels of development a little bit. But before we do that, let's frame our conversation a little bit. You open your talk by talking about React's age and how React just turned 10 years old. How does that kind of maturity of a frontend framework cause problems for developers? Ruben Casas: Well, it is actually not the age of React. I just added that as a fun topic of conversation. React is becoming ... Is turning 10 years old next May and it's not about React being old, it's about ... We've been building applications with React for a while now and that means that the applications are bigger, they're getting old, there is a lot of tech debts. So it's no problem with React itself, it's more about the scale and applications are aging right now. Noel: I see. I see. So do you think if a company had started their React journey much later, do you think it's less likely they'll be finding themselves in these kind of problematic spaces because it's more fresh code base? Ruben Casas: Yeah. Well, it depends. Actually, this is the only time I'm going to say, it depends during this talk, just check me. Well, if you are building a brand-new application with React and you're using the best patterns, I think it should be okay to a certain extent. The problem is when you start having multiple developers, when you have multiple teams, and again going to the problem is not the technology, the problem is coupling and also the organizational issues. But the problem with this is we have worked on a project where things start getting slower, everything worked fine at the beginning. Everything was like, "Okay, we are building fast, we're shipping products to our users, everyone is happy." But there is a point where the application starts to get slower, not user experience, but mostly changes start to get slower. The CICD pipelines start to get slower because there are too many changes, too many lines of code, et cetera. Features, they start getting duplicated. So you have a lot of a legacy code here and there and there is no ownership. You have a bunch of dependencies, especially with single page applications, which is something that we're going to be talking about in the podcast today is when you have a single page application, every single line of code increases the size of your application. Even if you do code splitting, you are adding more dependencies, et cetera. So it is more like the process of creating applications. It's more like the natural evolution of applications where you start having issues and with some of those issues could be solved. This is why many companies have turned to micro-frontends to see, "Oh, actually a micro-frontends are solution for some of these problems." What I always say is please try other options. Don't go to micro-frontends immediately because it could be that you could solve your problem with a modular monolith. For example, you could solve your problem with a monorepo. Micro-frontends are the top four, the largest companies, most complex products where you can potentially solve those issues. Noel: From the typical dev's perspective, what does a micro-frontend architecture look like? How's it set up? What does the source control look like? Ruben Casas: Well, source control is an interesting one because it doesn't really matter in this case. You could be a monorepo as well. It could be multiple repositories. That's one of the misconceptions about micro-frontends. It could be monorepo's and micro-frontends actually play really nicely together. So it's not about the source control and where you put the code, it's more on how the teams are creating the application. So the definition of micro-frontends is an architectural pattern. It's not the technology and this is where the misconceptions and the issues understanding this pattern come and it's because people mistaken the architectural pattern and the actual implementation, like the technology that is used. But the architectural pattern is allowing you to basically split the application into smaller pieces that can be deployed by independent teams and deploy independently. That's more or less like the basic definition, but I didn't say any technologies there. An architectural pattern splitting the application and the implementation is different from the actual pattern. Noel: What are the main benefits then of having this split up from an organizational perspective? Why do we want to have teams have autonomy to be able to deploy the frontend that they are working on more specifically? Ruben Casas: I'll say the main benefit is first, is meant to solve a problem. So if you don't have a problem, you're not going to see any benefits implemented micro-frontend. So the first thing that you need to ask yourself and your companies is do we have a problem? The answer is yes. Okay. The problem is we are basically having too many issues deploying because everybody's waiting for changes. The CICD pipeline is taking too long and also coupling, which is one of the main issues, which is everything is mixed everywhere and if you make a change here, it's changing somewhere else. So one of the main benefits is that independence. But before you achieve the independence, you need to decouple it. Before you have a distributor system, you need to decouple it first because if you're trying to deploy independently and you're still tightly coupled to other systems or code or libraries or other frontend applications, then you end up with something which is absolutely terrible is worse, which is a distributed monolith where you deploy independently but you still have to go through the process of arranging, talking to people about how are we going to deploy? So that is what you should avoid, you need to decouple first. Having the applications in a state where you can actually deploy them independently. Then the benefit is team autonomy. Teams can deploy to production, they don't need to talk to a release, train, they don't have to wait until it's ready, they just can't deploy quicker. The blast radius is smaller because you deploy something that is not going to affect the rest of the application, which is one of the main issues with monolith. You deploy monolith, you deploy the entire thing and you don't know if you are deploying something that's going to break the entire application. So it's more self-contained. Noel: Got you. So when we're talking about decoupling, disparate parts of the frontend, what are we talking about exactly? Because it seems to me that a lot of the frontend coupling would be unified button components, unified forms, so you have consistent style and feel across the app and I feel like that's a thing people aspire to. They want good component abstractions because it makes it cleaner and again they have a consistent feel for their brand. Is that what we're talking about, like pulling apart or is it more like how the systems interact with APIs and other layers of the stack? Ruben Casas: So coupling has two things. So the first is components, as you mentioned, they brought us closer to a system that can be reusable and that be atomic self-contained. If you're not using a component library like a design system or component library, you should because that helps you make your atomic components self-contained and maintainable. Now when we look about the coupling that happens after you start composing those components, it goes more towards the business logic and the business domain, and this is very important with micro-frontends and any distributed system if you're familiar with microservices, is that you should be developing your applications aligned to a business domain. So business domain is a self-contained unit that is owned by someone, in this case could be a team and that is a single responsibility for them to maintain and deploy this. So that is the organizational part. So decoupling will be separating out your business domain and ensuring that people are responsible for parts of the application. Now the technical part is how do we ensure that those different composed applications of different components do not link to each other or have indirect communication with things that shouldn't need to be aware of. So that is where the decoupling of those business domains starts to apply. Where you need to ensure that you are not calling a third party API without a proper interface. You are not passing props down from one component because at that point you are coupling to that component. So it's more trying to self-contained as much as possible your business domain using the technology to do that. Noel: Got you. Is there again, say we're talking about a Net New company, is there a way that they can help them self set up for future success as they're writing there? Even if they're not planning on having it be disparate deployed frontends to begin with, but they think that they might need to at some point. Is there any patterns they can try to adhere to set themselves up for success in the future? Ruben Casas: Absolutely, and this question, should startups use microservices or micro frontends? I mean the answer is probably no. Because again, going back to, do you have a problem? At the beginning startups they don't really have a problem, they're quite small and they are like developing really quickly and putting the product out there. Pro microfit and all that stuff. So they don't really have a problem that point. But what you said is very important, whenever I hear someone say, "No, shall I use micro-frontends for my startups?" Probably not because you will just increase the overhead, you will increase the complexity of your application and you don't need that. You need to be fast and you need to be thinking about bigger problems, like making money. So what I recommend is you should start designing your application in a modular way. Even if it's not deployed independently, you should start creating your application and having a little bit of an architect mind, like having a little bit of design and thinking, okay, if I'm building the e-commerce example is probably one of the most common in microservices in micro-frontends is like if I have a product page, I need to ensure that that product page is as independent as possible and I'm not creating abstractions that are shared across the application and I don't know where they're coming from. So that's why React for example is really good. I mean React is great because it takes us closer to a modular reusable component and that from React to jumping to a micro-frontend or modular architecture is, I mean it's not easy, it's not simple, but it is better than having a monolith that doesn't have that concept of components and modular frontend. So yes, definitely you should start thinking when if you're starting a company or is a product is very early on in the development phase, ensure that you can modularize as much as possible. Noel: Is it as simple as user React don't use global state and have well abstracting components? Is that it or is there other accidental areas where you can end up with these tightly coupled components that are hard to break apart in the future? Ruben Casas: Yeah, you mentioned the share state. I think that's one of the main sources of coupling when you have global state because everybody is reading from the global state and you cannot render independently. So the state and the data, so the data is another one that is very important. I always say components and micro-frontends should load their own data because if you are loading data from a place, for example, making an API call in a global shared state and then passing the data down to the components, those components won't work independently. They depend on a shared global state that is providing data. So I usually recommend for micro-frontends load your own data, do not share global state as much as possible. I know that's a tricky one, but when I've seen people having bad times and really hard times implementing micro-frontends, it's because they're sharing state and they're again coupling to things that they shouldn't be coupling. Noel: I feel that there is some inherent-shared state that's always going to be needed on the frontend, especially if you're trying to have a seamless user experience, namely like authorization or is kind of what springs to mind I guess both authorization and authentication to some extent. What can the user do? How should the UI be rendered for them? What should they be able to click on? Is there an optimal way to have that kind of data stored and passed around between frontends if you're trying to have a smooth UX for the user? Ruben Casas: Yeah, there are certain things that are not like you cannot avoid having some sort of coupling, but that is intentional coupling. The authentication is something that is required for the frontend to work. What you can do is you can make a good interface. So it is not as bad as a shared library that shares and leak state and is a very indirect, there's no intentional communication. So if you keep an interface that is very well designed that you know where the communication flow is coming, in this case it's coming from the top and you have options. If it's not signed in, then the micro-frontend or the component should fall back to a default state where ... Well, if it's not provided then and it's working. There are certain cases where there will be global configurations. Thin management for example is another case, but there are many solutions for that. I mean you could pass events. For authentication, my recommendation is use HTTP only cookies. Having an HTTP only cookie means that a secure cookie means that you don't really have to pass it, you just get sent with the request and the micro-frontends are not aware of the authentication, it's just if it's there it will be sent. They don't have to do anything special about it. That's one example with authentication. But with the other examples it could be passing just events. Events are the most simple way of just passing information that it doesn't entirely couple you to the implementation. So events and what else? Passing callbacks, that's another one. Expose an interface and you expose it to the world and then communicate. Very similar to how microservices communicate. So I mentioned microservice a couple of times is because micro-frontends are basically the parallel to microservices, but in the frontend not exactly the same, but that's where the idea came from. Noel: It sounds like you're trying not to be overly prescriptive in recommending people start using micro-frontends if they don't have the need for it yet. What is a good sign that an organization may be feeling pain that could be resolved by a more modular micro-frontend deployment architecture? Ruben Casas: The first symptom is velocity. As I mentioned earlier, deploying starts to get slow even though that your CICD pipeline, you can have caching and you can have all of these brand new monorepo's with caching. There is always a limit and in computer science you can either parallelize or cache. So if you have tried caching and that doesn't work, still slow because your application is huge, then the next option is paralyzed. When you split into micro-frontends, it means that you can't just build them independently so you don't have to build them all at once and when you make a change, you don't need to build the entire application, you just build your small application. So that will increase the performance of your bills. Also, organization, I mean to be honest, this problem is mostly an organizational problem. When you have to talk to five different people to get a change merged or do you have to wait until five PRs have merged until this hot fix has been passed, et cetera. When you start having those issues, then okay, will independent teams work more efficiently? If we give them the autonomy that they want and for them to deploy will be eliminating all those problems of communication between teams stepping on each other's toes, having accidental changes, going to production or having back fixes that need to go really quick and I cannot do it because another team is unable to produce the ... Make the release or we are waiting on them to do something. So when you start having all those problems and at that point we're like, "Okay, let's try a more decoupled way," and you don't have to go all the way to micro-frontends again, try a monorepo. Monorepo's are great as well. You can cache and you can somehow sometimes deploy independently but compose a bill time, so the application still gets deployed as a single unit, but you can still have a little bit of independence. If that doesn't work, then move to independent deployments and runtime composition. Noel: In your talk you touch on the micro-frontend decision framework. Is this topic what we're talking about now, figuring out how to do that abstraction? Is that what that framework is or is that framework something else? Ruben Casas: This concept has been created by my good friend Luca Mezzalira who ... He's written one of the micro-frontend books and he's always talking about micro-frontends. Once you decide to go with micro-frontends, you need to make certain decisions, and how are you going to define micro-frontends? In our case, in our company, what is micro-frontend? It's a business domain, is this a root on the URL, is it a widget, et cetera. The second one, which is second part of this podcast will be the rooting in the schedule will be routed routing. The next one will be communication. We already touched on how to communicate and share state to micro-frontends. So there are many steps into the micro-frontends decision framework. Another one is how to compose them a run time. For example, when you have a single page application and you are deploying independently, well how do you load that application of runtime? That's another decision that you have to make how we compose them. You can do a server side as well. You can do server side composition, you can do client side, which is single page applications. One of the big tools that help you with this is module federation, which allows you to load JavaScript that runtime, just import something asynchronously from a URL and it works. It is a great tool. So you have all these decisions, we can focus on maybe the rooting part and Router 6 is especially really good at micro-frontends. So it's very good fit for micro-frontends. Noel: Yeah, yeah. Let's do that. Why might that be a good place for devs to start looking when they're thinking about a solution for this? Ruben Casas: A good place, I mean this is another problem, I mean organizations are different. So people when they want a solution, the solution for your organization might be very different to the solution for another organization. So what I recommend is think about your problems and if you decide to go with micro-frontends, start with the micro-frontends decision framework. Are we doing server side, client side? Are we doing what the routing routine solution is going to be? How are we going to communicate, et cetera. So start there. Start with the micro-frontends decision framework and then choose the technology. I don't really like recommending micro-frontend frameworks because those decisions have been made for you and because this problem is so specific to your organization, you are basically taking other people's decisions that might be really bad for you. So you could use a micro-frontend framework. There is single SPA, which is a framework, one of the main frameworks for micro-frontends and also Module Federation. Module Federation is not a framework. It is more like a tool where you can build a framework on top of it, but there are many, I don't recommend any particular one. I recommend you to do your homework and decide what is good for you and your company and then choose the technology based on that rather than the other way around. Choosing the technology first and then see if it that solved a problem. I don't recommend that way. Noel: Yeah. Regardless of that decision tree. I feel like most devs are going to end up in a space, especially if they're using React or they've got to figure out how routing is going to work. So that's probably, is a good place for us to focus a little bit. How does React Router 6 kind of help with this problem? Ruben Casas: Going back to how React is very good at components and encapsulating things and separating concerns and decoupling, well, React Router 6 especially is excellent at this and I think we had Michael Jackson coming and sharing about the React Router feature, which is probably the best feature, which is the nested routing. That is a great feature because basically it allows you to map smaller parts of the UI of the application to the URL. Splitting the application into smaller pieces. That's what micro-frontends are, and React Router 6 is already giving you that power of splitting into smaller pieces that are mapped to a URL. So the URL becomes very powerful because you can't decide what to show or not to show on the page based on a URL segment. Michael did a great job of explaining what a nested routing is. So I will recommend if you listen to that episode, he will explain that. But it's not just that. There is another thing with React Router 6 that is very, very useful and is that they separated out the data loading from the actual rendering of the component. This is great because even Ryan Florence, he said the best thing that you can do is to decouple things pieces. If we separate out our frontend rendering from the data loading is great for micro-frontends because again, I said micro-frontends to load their own data. So first with nested routing, we have the micro-frontends on a separate URL segment and that URL segment can also load its own data using loaders with React Router 6.4. That is an amazing feature that we have there. So that's why it's a really good match for micro-frontends. Now this is going to single page applications. We at React Router 6.4 is for people who are still using single page applications and they want some of the features that Remix provides. So definitely check it out. If you're interested in Remix and you're like, "Well, actually I can't migrate to Remix yet." React Router 6 is pretty much remix for single page applications and I hope I don't even say something wrong and Ryan and Michael will be like, "No, you said that wrong." But for me, it's basically using Remix for single page applications because you have the concept of loaders, you have the concept of nested routing, you have the concept of actions. It's great, so it's a great match because you already have that division, that separation of concerns and that separation of the different parts of the application. Noel: For listeners who haven't delved into this space, can you elaborate a little bit on why having loaders at that routing level is so powerful? Ruben Casas: It simplifies your application a lot. So if you think about how we use fetching inside components, you will be doing a fetching inside usually in React a use effect, which is people have problems with us and it's very complex, but things happen if you use effecting correctly, then you need to handle your own state. You need to handle, "Okay, is this loading, was an error or is it data ready?" If we move this to the router to React Router 6, it means that we don't have to worry about the control of the state. The data is loading before the component renders. This is another great feature, even before your component renders, the data is already been fetched for you in the loader and then you don't need to worry about errors because errors are handled by React Router, you just need to throw an error and then the error boundary will catch it. Also, the loading is another one. There is no loading, there is no spinners. In React Router 6, there is only one at the beginning because obviously you need to load the bundle and you need to load the application for a single page application. But after that, there are no spinners. Why is that? There are no spinners because you are fetching before you render. So before you render the component, you don't need to show a loading spinner, you just execute the loader and the loader will just ... Once the date is ready or once there was an error, you will just render the component. So this is a mix, I mean this is ... Or Remix, I mean this is the same concepts from Remix, it's just they have been applied to single page applications. Noel: Can we talk a little bit then about that concept of have having the data all loading before the component renders and push it a little further in regards to SSR, Server Side Rendering? Is there good ways to do SSR in this micro-frontend friendly framework? Is that helpful, beneficial? Ruben Casas: Yes. I mean it is harder definitely. Going back to the loading the data, I mentioned there was a spinner at the beginning, the only one. If you use the Server Side Rendering framework, that spinner goes away. There is no spinner because the data is fetched on the server. Now Service Side Rendering a micro-frontends ... Well, let's talk about service side rendering first and then Remix. So Service Side Rendering in general? Yes, it is definitely possible. Actually the micro-frontend framework I worked at Amex that was server side rendered. So it was a traditional, very similar to Remix, very similar to Next.js where you have server side rendered and then you hydrate the page in the frontend on the browser and then you just have client side render afterwards. It's definitely possible. Actually that framework was based on React Recruiter 3, which was great by the way. React Route three was the best version and now I think React Router 6 just picked up where he left. So we can save link nor four and five. So it was great and React again, because React Router is so good at splitting the application, I can know by just looking at the URL, what I need to render. So it's definitely possible. The thing with Remix is obviously Remix doesn't use Webpack, so it's not compatible with Module Federation. I know they're trying to do some support with Webpack, so that's the first challenge. So having something that works with their bundler, it hasn't been done. It's not that is not possible. It is possible, but it has to be done and it's a bit complex, so it requires a lot of work, but it's definitely possible. Actually one of my friends created a POC on having Remix using micro-frontends. That POC had a really simple concept sharing just libraries and doing a lot of monkey patching and it worked. So it is possible, it's just Service Side Rendering adds another level of complexity, which definitely has to be worth it. If your application definitely needs Service Side Rendering, then yeah, it's possible. Noel: I think that that makes sense and it's probably again, another piece of the journey here if one is really trying to optimize their development flow and performance at the same time. But yeah, it can be a tricky thing if you're trying to lift an existing code base to kind of function that way, but I think it might make some of these other problems we talked about, like auth state and things a little bit easier to deal with. You don't have to think about it quite the same way, but it's going to depend like you said, on a given application and architecture. I'm going to put on my devil's advocate hat a little bit here. So I feel we have a lot of horror stories of devs when they're working on systems that have probably been broken up into microservices on the back end, maybe a little bit too early in the process or when the need wasn't there and they didn't feel that they derived as much benefit as they'd hoped and instead they just wound up in this state where it was harder to do change tracking and get deployments out the door and just coordinate code changes in general, is that same problem often encounter with micro-frontends or does that help with deployments and migrations in any way? Is there good material on that at all? Ruben Casas: Yeah, absolutely. I think you mentioned something very important, very crucial there. It's that they were using it when they didn't need to use it. So that was the first mistake. A lot of people who had a really bad experience with micro-frontends and microservices is because they're using it for something that is not solving their problem, they're just using it for different reasons. So that's one, you need to make sure it's solving a problem. The second one is distributed systems by design that are more complex, you will encounter more things to maintain. They are a bit more difficult to understand because they're distributed. The complexity has to be worth it. So unless you have a big problem and that you know problem is being solved by a distributed system, at that point you will be like, "Okay, I am happy with the complexity." The problem is people have the complexity of a distributed system and they're not seeing the benefits of that distributed system because they have introduced coupling into that distributed system. So you're basically removing all of the benefits without any ... Plus all the complexity. So you end up in a really bad place. To be honest, I have heard a lot of stories with micro-frontends as well and microservices. People who hate them because they were like, "This was hell, it was really the bad," but I haven't heard anybody who had a good implementation and this is the key, having a good implementation of a microservice or micro-frontend architecture is hard. It is very hard to do. But if you do it well and if it's solving your problem, then that complexity is definitely worth it. But yeah, you need to do it properly and doing it properly is the problem, it's very hard. Noel: Can we talk a little bit about, I guess, migrations and deployments? Again, say you've got an API that's changing upstream or something and you have to deploy two frontends at near synonymous time, or even there's the handoff layer is changing in some way, have some change in off patterns or something now and the two frontends need to communicate. Is there a way to ease that pain or is it going to be totally dependent upon a given architecture? Ruben Casas: Well, if you cannot avoid the coupling, if there is a case where there is definitely coupling, you have two options. One is, well, as a normal monolithic application, we have to update every single piece, but it's challenging. But also micro-frontends can be versioned. One really good trick that you can have with micro-frontends is you can use semantic version in ranges and you can have a system where it'll be like, okay, these micro-frontend hasn't been upgraded and there is a break in change. Well, we have two versions, one version that is a new one that is compatible and it works with the rest of the application and one that hasn't been migrated yet, that gets more complex, very, very complex very quickly as well. So having multiple versions is possible with micro-frontends is very useful for like AB testing experimentation. Rollbacks is great if you have versions, but it gets really complex very quickly as well. But in that case of a breaking change, then the versioning could also be really helpful because you just bump one of the major versions of one micro-frontend and then you ensure that the rest don't upgrade yet until they're ready. So they're backwards compatible, et cetera. Noel: I've got a note here about the strangler pattern and the reverse strangler pattern. Can you tell me a little bit about those? Ruben Casas: Yeah, so micro-frontends are also great for migrations in terms of migrating from a legacy system to a new system. If we go back to 2014, 2015 when React started getting popularity, the common thing that was started happening was like people start leaving AngularJS and migrating to React. There are two approaches to this. One is you can be like, "Okay, React is great, let's migrate and we are not going to be doing features for two years, and once the migration is done, we will start doing features again." That's never going to happen. That people products and companies are never going to buy into that. I'm sure that some people manage to do that somehow, like migrating everything at once, but that's not realistic. So there is a pattern called the strangler pattern, which is, I think it's after this tree in the Amazon or something where a tree starts consuming the larger tree from the bottom up. So until the new tree emerges from the tree that consume the old one. So this parallel in migrations is, okay, so we have a really old application and we want to start migrating pieces of the application until we completely replaced it. So it's not a Big-Bang migration, it's an incremental migration. I love this quote about Big-Bang migrations. I think Martin Fowler has said, "The only thing that is guaranteed with a Big-Bang migration is a big bang." So incremental migrations are the way to go. Now there is a separate variation of the strangled pattern, which is the strangled pattern is like you have the old thing and you start changing small pieces until you replace it. The reverse is, okay, let's change everything, let's change the foundation, let's do the big rewrite and then just put the monolith or the legacy application inside that new system or new better architected application. Then we start shrinking that monolith. We start removing pieces until it disappears and you just get the new one. I prefer this one because you get the benefits of the new architecture and the new technology straightaway. If you are migrating to React, then the new shell or the new patterns are there from day one, and then you just need to start removing the legacy one by one. The problem with that is, it's more challenging, it's more difficult to do because you need somehow to load the monolith or the legacy application inside the new architecture. That's not always possible. But this is where micro-frontends come really handy because micro-frontends allow you to load applications a run time that are nothing to do with the application. They're completely separate, even different Webpack bundles, et cetera. So what you can do is the new application will have all the brand-new language or whatever, and then you load the legacy monolith through micro-frontends like composition, for example, Module Federation, which is client site composition. Then that allows you to start removing pieces until it's completely gone. That's important part that at some point the migration will end and you end up with a brand-new application that has all the foundations and everything in there and the monolith just disappears. Noel: So how does that reverse the reverse strangler pattern? How does that end up actually manifesting? Say you're a user, right? You're like the whatever. The landing page is in the new ... Is it on new microphone, but then you click on ... You go to the product listing page or something. That thing hasn't been converted yet. Are you effectively switching between which application you're interacting with or is there a clean way to have both of them running at runtime in the user's browser? Ruben Casas: Yeah, there is both of them. So one is the URL, so the root of the application will load either the old one or the new one. Then the difficult part to get right is the boundaries when you cross from one to the other, some implementations will do a refresh of the page, but that's not a great user experience, but it is possible to have client site navigation still working. That's something that I managed to do with Module Federation and a distributed router. So basically just ensures that somehow the client site navigation remains. So there is no user experience impact. But the other one is also possible. You could, for example, load a widget from the old application inside the new application on the same URL, so the same route of the URL. That is also possible. That's possible because micro-frontends are encapsulated and you can load them a synchronous runtime. So you can load this widget that comes from the either new or old application inside the same page and they can live together under the same page URL. Noel: So if there are listeners listening that want to start exploring how, or the notion of starting to do a slow piecemeal migration that they can ship away at, where would you recommend that they begin? What tools should they start looking at? Ruben Casas: So if they're using a single page application, that's probably the simplest one because you can just look at Module Federation and start integrating and also React Router 6 for that URL moving from one to the other. React Router 6 is amazing at that and you can have nested routes and matches of star patterns, really, really cool. If you are using Service Side Rendering, then things start getting a bit more complex. But it's also possible, you can have ... There is some AWS resources where you can have micro-frontends on AWS that basically create all of these same patterns, but introducing Service Side Rendering. Resources out there, this is a big problem with micro-frontends is there are many, but there are so specific to companies that that'll be like, "This is how I did it." It's more like ... But technology-wise, look at the building micro-frontends book from Luca Mezzalira that I mentioned him earlier is very agnostic in terms of technology. He focuses a lot on the actual organizational problem and how to implement micro-frontends. He also talks about Module Federation. So basically Module Federation is my favorite tool for micro-frontends because it's very simple. If you don't like Module Federation and you don't like micro-frontends, basically it's an import, it's like a normal import, so you can't just remove it. So it's great for that. Yeah, I also recently did a workshop on introduction on micro-frontends and React Router 6. I might just leave the link. Very rough, two lessons on how to get started with this. Noel: Nice. Awesome. Yeah, well have links to that. We'll have links to the book you've been talking about hopefully and links to those podcast episodes that we referenced in the show notes, so people can go check them out. Is there anything else you want to point listeners to at all, Ruben? Ruben Casas: No, I think that's it. I mean, I'm always happy to talk about this. It's like passion talking about micro-frontends and routed systems. So yeah, any questions? I'm really happy just to talk and something I want to say to end, it's like you'd be surprised how many people are actually using micro-frontends today. It's not something that people talk about. It's like, "Oh, it was like ... in 2019, 2020. It was like, oh, micro-frontends. Are they here yet? People implementing?" Actually the people implementing are really quiet. Every time I talk to someone at a large company, they'll be like, "Oh, yeah. We are using micro-frontends. Oh, yeah. We are using it for this. It's great." So you'll be surprised how many companies are using them today in production. So something that people don't talk about enough. Noel: Yeah, no, I think it's probably one of those things where when it's working well as a user you don't really notice it's happening. Right? It just kind of like everything is chugging along nicely, but Awesome. Cool. Well, thank you so much for coming on and chatting with me, Ruben. It's been a pleasure. Ruben Casas: That's amazing, Noel. Thank you so much.