18 Knowledge Point Series Based on Ddd Microservice Design Examples

18 Knowledge Point Series - Based on DDD Microservice Design Examples #

Hello, I am Ouchuangxin.

In order to better understand the design process of DDD, today I will use a project to guide you through the strategic and tactical design of DDD, going through the entire process from domain modeling to microservice design, and together we will master the main design process and key points of DDD.

Project Basic Information #

The goal of the project is to implement an online leave and attendance management system. The functionality is described as follows:

The person requesting leave fills out a leave application and submits it for approval. The application is verified based on the identity of the applicant, the type of leave, and the number of leave days. It is then submitted for approval to the next level based on the approval rules. If it is approved at each level, the application is considered complete. Otherwise, it is rejected and returned to the applicant.

After verifying the leave data according to the attendance rules, the attendance data is validated and the attendance statistics are outputted.

Strategic Design #

Strategic design is the process of analyzing user journeys, identifying domain objects and aggregate roots, clustering entities and value objects into aggregates, and establishing the domain model.

The methods used in strategic design include event storming, which involves several main processes: product vision, scenario analysis, domain modeling, and microservice decomposition.

The recommended participants in the strategic design phase are domain experts, business stakeholders, product managers, architects, project managers, development managers, and testing managers.

1. Product Vision #

The product vision is the top-level value design for the product. It aims to align the product’s target users, core value, and unique selling points in order to prevent the product from deviating from its intended direction.

During the event storming, all participants express their opinions on each point by writing them on sticky notes and placing them on a whiteboard. The facilitator of the event storming will discuss each sticky note and consolidate and unify diverging opinions, resulting in the product vision diagram shown below:

img

We can summarize this product vision diagram into the following paragraph: In order to meet the needs of internal and external personnel for online leave application, automated attendance tracking, and external personnel management, we are building an online leave and attendance system. It is an online leave platform that can automatically track attendance. It supports both internal and external leave applications and manages leave requests and periodic attendance analysis for both internal and external personnel, unlike HR systems that only manage internal personnel and can only be used on the intranet. Our product can be used on both the intranet and the internet, enabling consistent management of internal and external personnel.

Through product vision analysis, the project team has unified the system name, “Online Leave and Attendance System,” clarified the project goals and key features, and identified the key differences from competitors (e.g., HR systems) and its own advantages and core competitiveness.

Product vision analysis is valuable for startup systems to define construction priorities, unify team building goals, and establish a common language. However, if your system goals and requirements are very clear, this step can be skipped.

2. Scenario Analysis #

Scenario analysis starts from the user’s perspective to explore typical scenarios in the business domain. It produces scene categorizations that need to be supported in the domain, use case operations, and dependencies between different subdomains to support domain modeling.

Project team members use event storming to analyze user journeys for leave application and attendance. Based on the journeys and scenario analysis of different roles, they comprehensively map out all the operations, commands, domain events, and external dependencies that occur from frontend operations to backend business logic.

Now, I will use two scenarios, leave application and personnel, as examples.

First scenario: Leave Application

User: Leave Applicant

Login to the system: Obtain leave applicant information and access rights data from the authorization microservice and complete the authentication process.

Create a leave request: Open the leave application page, select the type and start time of leave, enter the leave information, save and create the leave request, and submit it for approval.

Modify the leave request: Query the leave request, open the leave application page, modify the leave request, and submit it for approval.

Submit for approval: Obtain the approval rules, assign the approver to the leave request based on the approval rules and the personnel organizational relationship.

Second scenario: Approval

User: Approver

Login to the system: Obtain approver information and access rights data from the authorization microservice and complete the authentication process.

Retrieve the leave request: Retrieve the leave requests under the approver’s name and select a leave request.

Approval: Fill in the approval opinion.

Step-by-step approval: If further approval is required, obtain the approver from the personnel organizational relationship based on the approval rules and assign them to the leave request. Repeat the above 4 steps.

Finally, the approver completes the approval process. After the approval is completed, it generates a domain event indicating that the leave application has been approved. There are two further business operations: sending a notification that the leave application has been approved, informing the leave applicant via email; and sending the leave data to the attendance system for verification.

img

The following diagram shows the analysis result of the personnel organizational relationship scenario, and the detailed analysis process and attendance scenario analysis are not described.

img

3. Domain Modeling #

Domain modeling is the process of analyzing the business and problem domains to establish a domain model. It guides the design of microservices boundaries by setting the context and helps with entity object design through aggregation.

Domain modeling is a convergent process that consists of three steps:

  • The first step is to identify domain entities and value objects.
  • The second step is to identify the aggregate roots and establish aggregates based on the dependency relationships between entities, value objects, and aggregate roots.
  • The third step is to define the bounded contexts based on business and semantic boundaries.

Let’s go through each step in detail.

Step 1: Identify Entities and Value Objects

Based on the scenario analysis, analyze and identify the entities and value objects that initiate or generate these commands or domain events. Collect the commands and events related to entities or value objects into the entities.

The following diagram shows the relationship between entities and commands after analysis. Through analysis, we found the following entities and value objects: leave form, approval comments, approval rules, personnel, organizational relationships, card swipe details, attendance details, and attendance statistics.

img

Step 2: Define Aggregates

Before defining aggregates, identify the aggregate roots. From the above entities, we can identify “leave form” and “personnel” as two aggregate roots. Then, identify the entities and value objects that are closely dependent on the aggregate roots. We found that approval comments, approval rules, and leave forms are closely associated, as well as organizational relationships and personnel.

After identifying the relationships between these entities, we found that card swipe details, attendance details, and attendance statistics do not have an aggregate root. You will often encounter this situation when domain modeling, and for such scenarios, we need to handle them differently based on the circumstances.

Card swipe details, attendance details, and attendance statistics are independent of each other but collectively perform the attendance business logic with high business cohesion. We group these closely related entities into the “attendance” aggregate. In microservice design, we still use the design and analysis methods of Domain-Driven Design (DDD). Since there is no aggregate root to manage the entities within the aggregate, we can manage the entities using traditional methods.

After analysis, we have established three aggregates: leave, personnel organizational relationships, and attendance. The leave aggregate includes the leave form entity, approval comments entity, and approval rules value objects. The personnel organizational relationships aggregate includes the personnel and organizational relationships entities. The attendance aggregate includes the card swipe details, attendance details, and attendance statistics entities.

img

Step 3: Define Bounded Contexts

The personnel organizational relationships aggregate and leave aggregate jointly complete the leave business functionality, so they belong to the same bounded context for leave. The attendance aggregate constitutes its own bounded context for attendance statistics. Therefore, we divide the business into two bounded contexts: leave and attendance statistics, and establish separate domain models for leave and attendance.

4. Microservices Decomposition #

In theory, each bounded context can be designed as a microservice. However, multiple external factors need to be considered, such as single responsibility, separation of transient and stable business, non-functional requirements (such as scalability, version release frequency, and security), package size, team communication efficiency, and technical heterogeneity.

In this project, we primarily consider the single responsibility principle when dividing microservices. Therefore, based on the bounded contexts, we can decompose the system into two microservices: leave and attendance statistics. The leave microservice includes the personnel organizational relationships and leave aggregates, while the attendance microservice includes the attendance aggregate.

With the strategic design completed, we have established the domain models and defined the microservice boundaries. The next step is tactical design, which is the design of microservices. In the following sections, we will use the leave microservice as an example to explain the design process.

Tactical Design #

Tactical design is the process of designing microservices based on the domain model. This stage mainly involves organizing the domain objects within the microservice, defining the relationships between domain objects, determining their position in the code model and layered architecture, establishing the mapping between the domain model and the microservice model, as well as the dependencies between services.

The recommended participants for the tactical design stage are domain experts, product managers, architects, project managers, development managers, and test managers, among others.

The tactical design includes the following two stages: analyzing microservice domain objects and designing microservice code structure.

1. Analyzing Microservice Domain Objects #

The domain model consists of various domain objects, each carrying significant business attributes. To implement the domain model in the context of microservices, further analysis and design are necessary. Building on the event storming exercise, we further refine the domain objects and their relationships, and supplement any business and technical details that may have been missed during the event storming.

We analyze which services should exist within the microservice. How should the services be layered? How should application services be composed and orchestrated? What entities and methods should be included in the domain services? Which entity is the aggregate root? What are the properties and methods of the entities? Which objects should be designed as value objects, and so on.

Service Identification and Design

Commands from the event storming exercise represent external operations and business actions, which correspond to the capabilities provided by the microservice. These commands can serve as the starting point for service identification and design. The specific steps are as follows:

Design application services based on the commands, determining the functionality and composition of the application services, including the domain services or application services of other microservices within the service collection.

Design domain services based on the functional requirements of the application services, defining the domain services. It should be noted that application services may be composed of multiple aggregated domain services.

Based on the functionality of the domain services, determine the entities and functionalities within the domain services.

Design basic properties and methods for the entities.

In addition, we also need to consider the asynchronous processing of domain events.

As an example, I will use the action of submitting an approval to illustrate service identification and design. The general process for submitting an approval is as follows:

Based on the type and duration of the leave, query the leave approval rules and retrieve the role of the next approver.

Based on the approval role, retrieve the next approver from the personnel organization relationship.

Assign the approver to the leave application and save the approval rules in the leave application.

Through analysis, we need to design the following services and methods at the application layer and domain layer.

Application Layer: SubmitApproval application service.

Domain Layer: The domain services include QueryApprovalRules, ModifyLeaveProcessInformation, and QueryApproversBasedOnApprovalRules, which are located in the Leave and Personnel Organization Relationship aggregates, respectively. The LeaveApplication entity has the method ModifyLeaveProcessInformation, and the ApprovalRules value object has the method QueryApprovalRules. The Person entity has the method QueryApproversBasedOnApprovalRules. The following diagram illustrates the services we have analyzed and their dependencies.

img

That concludes the process of service identification and design. Next, we will design the objects within the aggregates. Objects in Aggregates

In the leave application aggregate, the root is the leave application.

After multiple levels of approval, the leave application will generate multiple approval opinions. To facilitate querying, we can design the approval opinions as entities. After the leave application is approved, it will generate a domain event for leave approval, so there will also be a leave event entity. The leave aggregate includes the following entities: approval opinions (recording the approver, approval status, and opinions) and leave event entity.

Let’s analyze the value objects in the leave application aggregate. The data of the leave applicant and the next approver come from the personnel entity in the personnel organization relationship aggregate, which can be designed as value objects. Personnel types, leave types, and approval statuses are enumeration value types, and can be designed as value objects. After determining the leave approval rules, the approval rules can also be used as value objects for the leave application. The leave application aggregate will include the following value objects: leave applicant, personnel type, leave type, next approver, approval status, and approval rules.

Based on the above, we can draw an object relationship diagram for the leave aggregate.

img

In the personnel organization relationship aggregate, we can establish the organizational relationship among personnel by using the organization relationship type to find the superior approval leader. The root is the personnel. The entity includes the organization relationship (including the organization relationship type and the superior approval leader). The organization relationship type (such as project manager, department head, general manager, etc.) is a value object. The superior approval leader comes from the personnel root and can be designed as a value object. The personnel organization relationship aggregate will include the following value objects: organization relationship type and superior approval leader.

Based on the above, we can also draw an object relationship diagram for the personnel organization relationship aggregate.

img

Object List in Microservices

After determining the attributes of each domain object, we can design the code objects of each domain object in the code model, including the package name, class name, and method name, and establish a one-to-one mapping relationship between the domain objects and the code objects. Based on this mapping relationship, relevant personnel can quickly locate the code location where the business logic is located. After the above analysis, we can analyze the object list in the microservices as shown in the following diagram.

img

2. Designing the Code Structure of Microservices #

Based on the code model of DDD and the package, class, and method where each domain object is located, we can define the code structure of the leave microservice and design the code objects.

Application Layer Code Structure

The application layer includes application services, DTOs, and event publishing-related code. The LeaveApplicationService class implements application services related to the aggregate, and the LoginApplicationService encapsulates application services for external microservices authentication and permissions.

A reminder here: if the application service logic is complex, one application service can be implemented in one class to avoid excessive code in one class, which is not conducive to maintenance.

img

Domain Layer Code Structure

The domain layer includes one or more entity classes, event entity classes, domain services, and factory and repository-related code for each aggregate. Each aggregate corresponds to a directory of aggregate code, and the aggregates are completely isolated from each other in the code and are coordinated through the application layer.

The leave microservice domain layer includes two aggregates: leave and personnel. The code for personnel and leave is placed in their respective aggregate directory structure. If, as the business develops, personnel-related functionality needs to be separated from the leave microservice, we only need to slightly modify the code package of the personnel aggregate, deploy it independently, and quickly release it as a personnel microservice. At this point, the domain objects, layering, and dependencies within the microservice are clear. The overall architecture and code model of the microservice are basically established.

img

Follow-up work #

1. Detailed design #

After completing the domain model and microservice design, we still need to perform a detailed design of the microservice. The main design includes the following: entity attributes, database tables and fields, entity-database table mapping, service parameter specifications, and functionality implementation.

2. Code development and testing #

Developers only need to follow the detailed design document and functional requirements, find the corresponding code location for the business functionality, and complete the code development. After the code development is completed, developers need to write unit test cases and perform service testing based on stubs to simulate the dependency objects.

Summary #

Today we have completed the entire process of DDD design through the online leave attendance project.

DDD strategic design starts with event storming, and then we need to identify domain objects such as entities, build aggregates by creating aggregate roots, define bounded contexts, and establish the domain model.

Tactical design starts with commands from event storming, identifies and designs services, establishes dependencies between different layers of services, designs entities and value objects within the microservice, identifies all domain objects within the microservice, and establishes mapping relationships between domain objects and code objects.

This can guide the project team well in microservice development and testing. In conclusion, do you now have a clear understanding of the entire process of DDD? If you have any questions, feel free to leave a comment for discussion.