Like, for example, for the Boolean, something that was mounting inside another component or we started having those sort of issues, right? Also, something that happened to us is that since that application had a lot of complex setup for the backend and really, really complicated needs for it to be started, we weren't actually able to kind of use them both at the same time, right? So what we ended up doing is to create this federated model that was used as fallback. It had really basic functionality that helped us to see how our application would work as a whole, I mean, completed with the information obtained from the other app, right? So but again, it was pretty much like we actually didn't know how that application would work with the host one. So there is where this concept of full-federated sites could have been useful for us at that time, because this creates sort of like a circular dependency between applications so that the host one not only becomes a consumer but also a producer. So as you can see here, for example, in the theater application, the home app, it's going to expose itself, right? And when we go to the application, we can consume also the host application and we can create a second script to be able to start our application with the host one, right? So that gives us a really fast development cycle and it will be pretty easy to see how they both interact when, for example, they need to, they have something coupled or some state or something that actually needs to interact with each other. It will be easier to test and even easy to test or use for end-to-end tests.
Also, I wanted to talk about some things for example, performance. And I think it's important to take into account several factors that we have when we import components from a federating model. For example, the first one is that it is really important to use dynamic imports to reduce initial bundle size and also be able to import and load these models only when they are needed, right? Also, the waterstrap applications to give webpack the opportunity to process the rest of the imports before executing the app and avoiding race condition. The most important one I think is dependency sharing because not specifying shared packages can result in duplications and slow down the experience. And not defining versions between shared libraries can also cause errors between the applications. And if there are libraries with internal state, we have to make sure to make them as singletons to ensure that we have only one instance running, right? And that is where also comes debugging because when you start having performance issues due to shared dependencies, we can use tools like Medusa where we can have a better understanding of how our microfounders are connected and especially what dependencies we are using and which needs their attention. For example, here it is telling us that a specific dependency can be declared as shared. And also something really cool that was introduced in Model Federation 2.0 is that the Chrome tools now, for the Chrome tools we have now a plugin, a Model Federation plugin that we can install and see how our application is connected and how our models are being consumed. So that is pretty cool for debugging because if something fails, you can see also what other applications can be affected, right?
Also for styling, what we did to keep our application coherent is to use the same UI kit and that allows us to reuse built components, avoiding customization, right? As much as possible. So if we needed to change something, we change it in the UI kit library. That way we avoided presenting the user something like Comic Sans in one page and Times New Roman on the other. Right. Also, routing is really important to take into account. In our application, what we did is to use the concept of a shell application. That actually is pretty much the host. And the sole purpose of it is to orchestrate the microfront, right? So the routing only works inside the host application. When we can actually import the models with lazy loading, render them with necessary and basically handle the routing as we needed. Other options you can use also can be like frameworks, for example, Single SPA. Single SPA allows you to mount and unmount components to improve performance and load them in specific places or specific routes, right? Finally, stage management. We had a really tightly coupled applications. So stage management was used basically from the producer application because we actually needed to get the state from there. We used hooks, which made it kind of easier to do. But I would say that if you actually want to go all the way, and if we probably would have been using models, not only because of the strangled pattern, but different use cases, there are also things like, for example, we could have used like probe drilling, pool solve, query parameters, local storage, anything that could have avoided to basically couple the applications. And we always need to try to basically decouple them.
Comments