Breaking the Frontend Monolith

broken-plate
portrait-image
In this article, you will learn about the challenges that arise when migrating a typical frontend monolith to microfrontends. You will hear about common practices from Domain Driven Design, that will help you draw boundaries in your monolith, which in the end allows you to divide your subdomains into microfrontends.

Migrating to Microfrontends

There are just very few reasons for going for a microfrontend architecture, whereas the most common one is scaling teams. Disclaimer: If you have less than 3 frontend teams, microfrontends will likely be overkill and not make sense for your organization. The main goal of microfrontends is only about making independent modules independently deployable as well.

The other reason for migrating to a microfrontend architecture is for migrating a JavaScript framework. For example, it makes sense to implement a microfrontend architecture when migrating AngularJS to Angular, because you can then create a hybrid application that uses Web Components to abstract away a JS framework. This is actually a real deal, because migrating big applications in the past was a total pain, because usually you had to do a rewrite, which takes all resources for months. With a microfrontend migration strategy on the other hand, you can gradually migrate subdomain after subdomain, or page after page and meanwhile you can still keep up with feature/bug requests.

Nevertheless, if you have to decide to go for microfrontends, then you should watch out for the most common mistake, which can make your entire architecture pointless. Micro frontends will only work if your application is already structured in very independent fine-grained libraries. Otherwise, a change in one part of your system will result in a deployment of all microfrontends, hence the benefit of independent deployment is totally gone.

big ball of mud

Therefore, we must start by creating a system that is already very independent in terms of dependencies in the code. We need to structure this so-called “Big Ball of Mud” in smaller modules, that have way less dependencies between each other.

good separation

It really looks simple, when it is just there as a diagram, but in the real world, dividing an application into independent subsystems is by no means trivial. I have a bad message and a good message. The bad one being that there is no perfect step-by-step guide to gives you a perfect separation. The good message is, that many people have faced this problem before and came up with many ideas that support us in finding possibly effective separations. Many of those ideas can be found under the Domain Driven Design philosophy, which I often view as a huge toolbox for bridging the gap between requirements and software architecture.

Implementing a Domain Driven Design Model

Domain Driven Design can be broken down to two main concepts: Strategic Design and Tactical Design. Whereas Strategic Design focuses on the bigger picture and the slicing of a big system into subdomains, Tactical Design is more about implementation details, such as design patterns and best practices. Therefore, Strategic Design is of bigger importance to us, when we talk about decomposing a system into subdomains.

But how do we create all those subdomains? Although, there is no direct answer that is always applicable, there are multiple tools, from the DDD toolbox, which will help us in identifying possible candidates for a good domain slicing. Another bad message: We have to look at the business processes. I know that this is something that no developer ever would want to do, but it is a total necessity, and you will see the benefit in a second.

Let’s have a look at a concrete example — a hotel software. A customer would book a stay for a few days online on a website like Booking.com, then a room service will be scheduled briefly before the scheduled check-in. After a successful check-in, the customer is greeted with a welcome drink at the hotel bar. Surely, after the stay, the customer will do a check-out.

domain slicing
Domain Slicing

In the figure above, we look into three areas — business processes, entities, domain agents — which will help us in identifying possible subdomains. As you see, there are no major commonalities in the business process itself. Maybe, Check-in and Check-out are related, but are likely better to be distinct subdomains. If we look at the entities, we can definitely see a lot of commonalities, because the booking is used in three distinct steps. If we look at the domain agents, or in other words the people involved in a business process, we can also see a that both the Check-in and the Check-out are done by a receptionist.

Now we are able to see commonalities and differences in many aspects on paper, hence a domain cut is easier. Frankly speaking, this makes the decision easier, but surely does not tell us what is the ideal domain cut. That is just something that is truly subjective with no right or wrong, hence we should try to start with a good intuition and then adapt the domain cut in an agile manner.

subdomains
Subdomains

In this example, I have decided to go with four subdomains. Booking, Room Service, Reception and Bar. This is could either be a good or a bad domain cut and nobody can really make a judgement, without knowing the exact requirements of the system. Now that the subdomains have been identified, we must talk about something non trivial again — Communication. Although, it would be perfect when the subdomains would not share any dependencies and work completely independent, the reality looks different. In reality, almost all subdomains have dependencies on other subdomains. In order to visualize the dependencies between the subdomains, we create a so-called context map.

context map
Context Map

As you see, the Booking subdomain is in the center of our context map, because all other subdomains depend on it. And that is no wonder because all subdomains have some dependency on the booking entity, which triggers a room service, and activates a voucher for a welcome drink at the bar, and the reception must be able to see all current bookings. This is definitely unfortunate since a change in the booking subdomain would trigger all subdomains to be rebuilt which has basically no deployment advantages in contrast to a regular monolith.

shared kernel
Shared Kernel

Luckily, there are many techniques in strategic design that help to minimize those differences. One of which being a Shared Kernel, that acts as a shared library, such that the direct dependency between subdomains is eliminated. But watch out, to keep your shared kernels as small as possible.

There are many other techniques, such as the Open/Host Service, or an Anti-Corruption Layer, which I recommend you to have a read on.

Duplication over Abstraction

There is just one topic remaining that we must talk about in order to be successful, when doing DDD. Inside a subdomain, we have a so-called ubiquitous language, which basically means, that the naming of the entities is equal to the domain language a domain expert would use. This ubiquitous language is valid in the boundaries of a bounded context, which most of the time is equivalent to a subdomain. It is a total necessity that the ubiquitous language is completely independent of other subdomains.

ubiquitous language
Ubiquitous Language

This means, that we can have a booking entity in multiple bounded contexts and the meaning of the entity can vary. For example, a booking inside the booking subdomain can consist of many fields, whereas the booking entity in another subdomain might only have few fields.

Sometimes, entities might look very similar or even the same, but here you must watch out to get away from the traditional OOP thinking and avoid making abstractions. Usually, in OOP we are taught that duplication is the root of all evil and abstractions are the rescue, but in the case of DDD duplication is not bad. Actually, duplication in DDD is a lot better than abstractions, because that way, subdomains can be more independent and that’s what it all is about in the first place.

Conclusion

The most important thing that must be done, when migrating to a microfrontend architecture, is a clean domain cut, such that the microfrontends share just few dependencies. This is the foundation to independent deployment, which is the main reason for a microfrontend architecture, hence a microfrotnend architecture should always be done with domain driven design.

Thank you 🤗

Thank you for reading this article! I hope that you enjoyed it and could learn something new and interesting.
If you have any questions left, don't hessitate to contact me on Twitter or LinkedIn to have a discussion.
Haven't subscribed yet? Scroll down and don't miss any new articles anymore.