41 Micro Frontend From Mvc Anemic Model to Ddd Rich Domain Model

41 Micro Frontend From MVC Anemic Model to DDD Rich Domain Model #

Hello, I’m Ishikawa.

In the previous unit of “JS之器” (JS Tools), we introduced tools that empower JavaScript development. Today, we have arrived at the last unit of this column, which is “JS之势” (JS Trends). In this unit, we will take a look at some trends in JavaScript and front-end development. In this lesson, let’s take a look at the concept of “Micro Frontends,” which has gained popularity in recent years.

From Microservices to Micro Frontends #

Before discussing micro frontends, let’s first take a look at microservices, which inspired the concept of micro frontends.

Microservices is an architectural pattern that was first introduced in 2011. Before the concept of microservices, web service development went through two phases: client/server (C/S) architecture and service-oriented architecture (SOA). Let’s start by understanding the C/S structure.

C/S Structure #

C/S structure, short for “Client/Server” structure, can be considered as one of the early system architectures in web development. At that time, most web development involved creating a few HTML, CSS, and JavaScript files which were then uploaded to the server via SFTP. These files were accessed and downloaded by client users through browsers over the network. As websites and web applications grew in scale, the simple C/S structure was no longer able to handle the complexity requirements of large enterprise web applications.

SOA Structure #

This led to the evolution of the C/S structure into SOA, which stands for Service-Oriented Architecture. SOA was born in the late 1990s and introduced a concept of a layered architecture through a service-oriented design. The top layer is the application, the middle layer consists of services, and the bottom layer includes the backend with business logic and databases.

In the SOA structure, we can see the design principle of componentization because in this structure, each service can be encapsulated. Each service is reusable, which means it can be used to build composite services or serve specific business objects independently. Services can have different levels of granularity and provide an abstraction layer, which means that the business logic and data do not have to be visible to the application. Overall, developers on both the service provider and consumer sides can independently develop and integrate based on contracts between services.

Microservices Architecture #

Over time, microservices architecture emerged around 2011 and gained popularity. At first glance, it is simply the result of the continuous evolution of SOA and shares many common characteristics with SOA architecture. For example, the concept of encapsulation, granularity, abstraction, and contractual protocol are also present in the philosophy of microservices architecture. However, the difference lies in the emphasis of microservices on domain-driven bounded contexts, collaboration, and DevOps. The arrival of microservices has had varying degrees of impact on business architecture, software development, and software engineering.

From a business architecture perspective, it is based on domain-driven design, which places more focus on designing for business objects rather than a procedural approach. The second perspective is from software development, where traditional service development models mostly relied on anemic domain models (ADM). With the rise of microservices and domain-driven design (DDD), there has been a shift towards rich domain models (RDM). A typical example of an anemic domain model is the MVC structure. However, you may wonder why MVC, which is commonly seen as a frontend development framework, is referred to as an anemic model in web backend service development. This is because in backend development, there is also a three-tier architecture consisting of Repository, Service, and Controller. These three layers are responsible for data access, business logic, and interface exposure, respectively.

Image

In backend layered development, data objects, business objects, and display objects only contain data and do not have any business logic, hence the name anemic model. On the other hand, the opposite of the anemic model is the rich model, which mainly refers to the enrichment of business logic. In other words, in the service layer, a Domain class is added on top of the Service class, which contains both data and logic. The Service class is then weakened and mainly responsible for calling logic, permissions, and transaction control.

At this point, you may wonder, isn’t Domain-Driven Design (DDD) something mysterious? From a development perspective, it seems to just replace the Service class with the Domain class. What impact does this have on the resulting service?

In fact, the main impact here lies in the design concept and development process. Let’s imagine under the traditional anemic model, service design is passive and hardly qualifies as design. It is more based on responding to frontend interface data requirements. We can even call it SQL-driven development. For example, when the frontend needs to display certain data, it requests the backend, and the backend developer then thinks about what SQL statement can be used to obtain the relevant data. Then, data access objects, business objects, and display objects are created or modified, and finally, the data is exposed through an interface to the frontend.

If it is a relatively simple application system, developing with this model is manageable. However, when faced with more complex business logic, this kind of design becomes difficult to maintain because even a small change in a data request may result in new code, much of which may be repetitive.

The main difference between domain-driven and SQL-driven is that domain-driven requires developers to clarify the entire business architecture, define domain models, and the attributes and methods included in the models from the beginning. These domain models are actually reusable business middle layers. Therefore, when developing new functional requirements, they can be built based on the previously defined domain models.

In addition to the changes in development design and process, microservices and DDD also change development habits from the perspectives of collaboration and software engineering. This modular service construction method allows each backend service to be designed and developed as smaller building blocks, achieving greater system flexibility. With support for DevOps, continuous integration, and deployment, it can also reduce development cycle time and improve operational efficiency. Many software companies and large enterprises have been promoting and transforming this architecture. However, the same idea has not yet matured in frontend web development.

Micro Frontend Architecture #

However, over time, in 2016, the concept of micro frontends emerged. If microservices broke the monolithic structure of the backend, micro frontends aimed to break the monolithic structure of the frontend. With this concept, different modules of the frontend can also be componentized and loaded based on page requirements and interact with each other. In addition, micro frontends also allow different frontend teams with different technologies, skills, and toolsets to independently develop a set of functionalities in their own encapsulated business domains.

Design and Implementation of Micro Frontends #

Now, before we discuss micro frontends, let’s take a look at the evolution of front-end system architecture.

Early websites were mostly “multi-page applications,” which means that end users accessed each individual page of the website, and navigation between pages was done through clicking hyperlinks. Whenever a navigation action was triggered, the page would refresh. The content and creation of pages were typically supported by a content management system (CMS), which is used to create, edit, and publish dynamic content, especially on the web.

In the early years, there were many popular CMS tools on the internet, such as WordPress or Drupal. CMS systems had two different user interfaces: one for public access and another for backend authors and editors. The business logic and content were primarily presented at the backend, and the output was a webpage containing HTML-formatted information for the public to view.

The workflow of a CMS is that content authors select templates and components for content creation in the backend. Once the page is built and the content is added, the author publishes the page, and it is delivered. Typically, a CMS is used in conjunction with a content delivery network (CDN) to cache and speed up page and resource loading time. Of course, this classic CMS approach is still widely used today, with many people using WordPress to create personal blogs. The popularity of CMS tools is attributed to their focus on information updates without the need for heavily interactive pages with extensive business logic.

With the rise of Ajax and subsequent technologies like HTML5 and CSS3, websites became more interactive, and rich internet applications began to emerge. Due to increased user interactivity, single-page application (SPA) technology gained prominence and became widely used in web development. While CMS can still be used in SPAs, its functionality is limited to content management rather than creating HTML pages. In this case, the front-end application takes on the task of page creation and rendering, while the CMS is responsible for content delivery. Such CMS is often referred to as a headless CMS.

SPAs are not limited to PC platforms; they can also be used on mobile devices and other embedded systems, and the content may need to be modified based on the client type, which may require the addition of a BFF (Backend For Frontend) adaptation layer. In addition to adaptation, the BFF can also be used for API composition or aggregation, service authentication or authorization, or building microservices on top of legacy systems.

Another issue with single-page applications is search engine optimization (SEO). Search engines typically rely on URL links to search for content. However, for SPAs, search engines can no longer easily find pages because there is no URL update when users navigate from one section to another. Google has developed powerful algorithms that can even crawl SPA pages. However, Google is not the only search engine used in the world, and there are still many search engines that cannot crawl HTML pages rendered on the server or client side.

To address this issue, the most common solution currently is to use both client-side and server-side rendering, which means that the front-end and back-end share the same template files and use separate template engines to render pages containing data. This pattern, combined with Node.js, is known as isomorphic JavaScript.

In the process of evolving from SPAs to micro frontends, we need to pay special attention to several points. The design of micro frontends typically involves considering four layers of architecture: system layer structure, application layer structure, module layer structure, and coding layer structure.

Image System-level architecture: This involves how we want the micro frontends to interact with other systems or applications (such as back-end or admin systems). The back-end system requires some type of integration, typically involving the use of microservices, BFF (Backend For Frontend), API contracts, mock APIs for development testing, and OAuth for authentication.

Application-level architecture: This includes the framework, design system, and practical tools, libraries, and programs used to build the micro frontend application itself.

Module-level architecture: This involves all the components and modules used as building blocks in the application, including the main application and sub-apps. Technologies like Web Components are important for micro frontend development because they provide modular support in front-end development. However, when using Web Components, it’s important to note that they are not an official W3C standard and there may be compatibility issues. Most development using Web Components is typically based on tools like Lit or Stencil to mitigate these risks.

Coding-level structure: This level of architecture involves development processes (including repository management, code merging, code commits, and pull requests), code quality, and coding standards. These are principles that should be considered consistently in micro frontend development.

Based on this four-layer micro frontend architecture, we can focus on the application layer’s app container, configuration, registration and discovery, central routing, and lifecycle management, as well as the coding layer’s development process, build and deployment process.

App Registration, Discovery, and Routing #

Although micro frontend architecture is a decentralized concept, a central app container is still important for creating a unified experience in which all components collaborate. In addition to defining an app container, it’s also important to have a mechanism for registering and discovering sub-applications, similar to the registration and discovery in microservices. Once there is a mechanism for registering and discovering sub-applications, the central app container can use routing to discover and redirect users to the correct content location.

App Lifecycle Management #

In addition to the aforementioned mechanisms, the lifecycle management of each individual sub-app is also important. In an app’s lifecycle, tasks to be handled include inserting, updating, or removing modules from the container, or handling key tasks related to component loading, updating, unloading, and error handling. This process starts with obtaining the configuration from the sub-app registry. When a URL change occurs, change events trigger the unmounting of existing sub-apps and the loading of new sub-apps based on the configuration details. When the URL changes, the new sub-app will be loaded to the host.

App Development and Deployment Management #

An efficient development process is important in any development work, and this is particularly true in micro frontend development. To maintain an efficient development pipeline, several key points can be checked and improved using various tools mentioned in the previous unit “JS: The Tool”. Tools like Jest and ESLint can be combined to check code functionality, structure, format, and quality. Similarly, package management and dependency management tools like NPM or Yarn can be incorporated into the process, code can be compiled using Babel, and the application can be bundled using tools like webpack. These can all be used in the build and deployment process to improve management efficiency.

Summary #

In this lecture, we have seen that the emergence of micro frontends is inseparable from the prior appearance of microservices and domain-driven design models. However, in the frontend, unlike the backend, the point is that the frontend is not the provider of services, but the consumer. Therefore, although micro frontends are inspired by microservices, both emphasize business domain-based design, component encapsulation, and modular development, they still have essential differences in their use cases.

At the same time, micro frontends are not completely decentralized, as we still need a main app container responsible for loading the sub-apps. Between the sub-apps, different from monolithic design, we need to spend more effort to ensure the registration and discovery of sub-apps, routing, and lifecycle management. Moreover, the more decentralized it is, the more we need a “consensus mechanism” among teams to ensure the management of development and deployment processes. However, the benefit of this is that we can have greater development freedom among sub-teams and, at the same time, ensure efficient collaboration in a scalable context.

Thought Question #

In micro frontends, each component is encapsulated independently. Do you know how to achieve communication between them?

Feel free to share your experiences, exchange learning tips, or ask questions in the comments section. If you find it helpful, please share today’s content with more friends. See you in the next lesson!