Many of you have heard about Domain-Driven Design (DDD) when it comes to decomposing a backend application into a collection of microservices. However, not many people know that this same strategy can also be applied to the frontend world, specifically micro-frontends (or how it is trendy to call them now – “distributed frontends”). In this article, I will show you how you can use DDD principles to decompose your frontend application into smaller and more manageable micro-frontends. By applying Domain-Driven Design in micro-frontend architecture, you can achieve better modularity, testability, and maintainability of your frontend codebase. Additionally, you can take advantage of micro-frontends’ benefits, such as independent development, deployment, and scaling of individual frontend modules. So, let’s dive into the world of DDD and see how it can help us decompose our front-end application into distributed frontends.
What is micro-frontend?
Before diving deeper into applying Domain-Driven Design principles to micro-frontends, let’s take a step back and define what micro-frontends are.
Similar to microservices, micro-frontends represent a way of breaking down a large and complex system into smaller, autonomous and independently deployable parts. In a micro-frontend architecture, the front end of a web application is decomposed into multiple smaller applications, which are known as micro-frontends. Each micro-frontend is a self-contained module that encapsulates a specific business capability or user interface element of the overall system.
In simpler terms, a micro-frontend is a small and self-contained frontend application that works together with other micro-frontends to build a larger, complex frontend application. Each micro-frontend can be developed, tested, and deployed independently, and can even be written in a different technology stack than the others.
What is front-end architecture?
Similar to any other software system, the front end of a web application requires a well-defined software architecture. As defined in “Documenting Software Architectures”, “software architecture is the set of structures needed to reason about the system, which comprise software elements, relations among them, and properties of both”.
In the context of front-end development, a software architecture defines the overall structure of the user interface, the components that make up the UI, and how they interact with each other. Essentially, every architecture is a decomposition into parts (elements) and relationships between them. Decomposition is a crucial aspect of software design, as it allows for the division of labour and knowledge among team members. By breaking down a complex system into smaller, more manageable parts, multiple people or teams can work productively together on different parts of the application. Furthermore, decomposition helps define how software elements interact with each other. It creates a clear boundary between different parts of the application and allows each part to operate independently.
In addition to the traditional front-end architectures like Model-View-Controller (MVC) and Model-View-ViewModel (MVVM), another architecture that has been gaining popularity in recent years is the Hexagonal Architecture, also known as Ports and Adapters Architecture or Clean Architecture.
At its core, the Hexagonal Architecture is based on the concept of separation of concerns. It provides a clear separation between the business logic of an application and the infrastructure components, such as the user interface, storage, and external services. This separation is achieved through the use of “ports” and “adapters”. In the Hexagonal Architecture, the business logic is encapsulated within “ports.” Ports are interfaces that define the input and output of the application’s core business logic. Adapters, on the other hand, are responsible for connecting the ports to the infrastructure components. Instead of the UI/view layer, the application has one or more inbound adapters that handle requests from the outside by invoking the business logic. Similarly, instead of a model/data layer, the application has one or more outbound adapters that are invoked by the business logic and invoke external applications.
However, there are some challenges that need to be considered when using Hexagonal Architecture in front-end development. One of the main challenges is that front-end development typically involves a lot of interaction with the user interface, which can be difficult to separate from the application logic. In traditional back-end development, the input/output ports and adapters can be more easily separated from the business logic, as they tend to be more clearly defined. In front-end development, it can be more challenging to clearly define these boundaries due to the highly interactive nature of user interfaces.
In the most generic form, this architecture can be represented as follows:
The micro-frontend architecture is also an architectural style where each component (micro-frontend) can be represented using hexagonal architecture:
Domain-Driven Design in micro-frontend
When decomposing a frontend application into micro-frontends, one effective approach is to break it down by business capability. These capabilities can be identified by analyzing an organization’s structure, purpose, and business processes. Each capability represents a business-oriented micro-frontend, with various components such as inputs, outputs, and service-level agreements. Once these capabilities are identified, micro-frontends can be defined for each one or group of related capabilities:
DDD has two concepts that are particularly useful when applying micro-frontend (and micro-service) architecture: subdomains and bounded contexts. DDD defines a separate domain model for each subdomain, which represents a part of the application’s problem space. Subdomains are identified using a similar approach as business capabilities, by analyzing the different areas of expertise within an organization. This results in subdomains that are often similar to business capabilities. A bounded context is the scope of a domain model, which includes the code artifacts that implement the model. In a micro-frontends architecture, each bounded context is represented by a micro-frontend or a group of related micro-frontends. By applying DDD principles to the decomposition of a frontend application, each domain model is owned and developed by a single team, which aligns with the concept of autonomous teams owning micro-frontends in a micro-frontends architecture.
When decomposing your application don’t build it around the existing communicational structures of your organization – instead, build your team and organizational structure to promote your desired architecture. It is also helpful to use data-driven decisions when drawing the boundaries:
- If you know that 80% of your bundle size for the subdomain is accessed only by 20% of the users, it might make sense to split this subdomain into two to reduce network bandwidth on the end device (considering that responsibility boundaries are still clear between the teams owning each subdomain).
- If you observe that adding new features to subdomain A always causes changes to subdomain B, it’s most likely a sign of pre-mature optimization – these subdomains must be merged.
- Sometimes you might notice that even though 2 subdomain packages are isolated and independent, they have so many common dependencies and behaviour that you basically duplicate the same code that needs to be downloaded by the user twice. This is when you need to externalize this logic into a library (widget) that will be deployed independently and shared between the teams. Such decompositions are usually tricky because it’s hard to define this package’s ownership – it would be owned by everyone or nobody (pick whatever is the worst). Introducing the platform team into your organizational structure might bring more clarity to the ownership model.
In conclusion, applying Domain-Driven Design (DDD) principles to decompose a frontend application into micro-frontends can lead to a more manageable and scalable architecture. By breaking down the application into smaller and more focused micro-frontends, organizations can achieve greater agility, as well as more easily allow for the development and deployment of new features. While DDD may be more commonly associated with decomposing backend applications into microservices, it is equally applicable to the frontend world. By understanding the benefits of a micro-frontend architecture, as well as the principles of DDD and other effective techniques for decomposition, organizations can create a frontend architecture that is both flexible and adaptable to changing business needs.
Be First to Comment