From Chaos to Elegance: Code Renovation Guide for DDD-Based Hexagonal Architecture | JD Logistics Technical Team

Preface

Taking advantage of the preparations for Double Eleven, I finally have some time to sort out my recent experiences.

In the past six months, I have been discussing more with colleagues about layered architecture, and then I have encountered two issues that touch my soul. One is how to build a layered architecture, and the other is how to implement DDD at the architectural level.

In order to talk about layering well, we need to understand the meaning of architecture.

A good architecture is to ensure the following two points:

  • Manage application complexity and reduce system entropy;
  • From a chaotic state of randomness to a state of organized order.

For example, if you go to the library to borrow books, if the various types of books cannot be well managed and classified, it will inevitably lead to chaotic library management and low efficiency, making the library unable to operate normally. The significance of the layered architecture is also here. When we face complex business needs, we need to better plan our package structure and dependency specifications, so that we can better manage our services and improve the maintainability of the services. Scalability ensures that our architecture takes business as the core, decouples external dependencies, and separates business complexity and technical complexity.

The traditional layered architecture includes MVC, and the hexagonal architecture that has been popular in recent years has been gradually accepted by everyone with the rise of DDD. If we talk about the relationship between DDD and hexagonal architecture, they belong to different levels of concepts. DDD is more methodological, focusing on domain modeling and business logic design, emphasizing the transformation of business requirements and domain knowledge into software design; and hexagonal architecture Architecture pays more attention to the overall architecture and modular design of the system, emphasizing the separation of internal and external system interactions. The combination of the two is a very good practical experience. The domain model in DDD is the core, and other layers (such as application layer and infrastructure layer) depend on the domain model; and the hexagonal architecture just provides a very good way for DDD. Good layering.

A brief talk about DDD implementation

For DDD, there is no so-called framework or scaffolding that can correspond to it. The fundamental reason is that DDD is actually a methodology, not a so-called framework. It provides us with a way to deal with business complexity:

  • Separate business complexity and technical complexity through architectural design;
  • Divide and conquer is achieved through bounded context, and the large system is broken down into several subdomains with high cohesion and low coupling;
  • Abstract the knowledge of business subdomains through object-oriented design patterns.

in conclusion:

  1. DDD's strategic modeling focuses on the division of subdomains and the definition of bounded contexts. Corresponding to implementation is the disassembly of packages, as well as the dependencies and combination relationships between packages.
  2. The tactical modeling of DDD mainly focuses on building blocks and flexible design. Building blocks are what we often call classes, objects, and combinations. Flexible design is our object-oriented design principle, resulting in a system with high cohesion and low coupling. Therefore, the implementation of DDD tactical modeling must be accompanied by developers’ in-depth understanding and application of design patterns.

Hexagonal layered architecture



1. App layer

The application layer is the top layer in DDD and is responsible for coordinating and organizing the interaction of domain objects. It receives requests from the user interface or external systems and forwards them to the domain layer for processing. The application layer is responsible for defining application use cases (Use Cases), handling transaction boundaries, and coordinating the operations of domain objects. It does not contain business logic, but rather the operation of converting requests into domain objects. The application layer can also include obtaining input, assembling context, parameter verification, exception definition, sending event notifications, etc.

2.Domain layer

It mainly encapsulates the core business logic and provides business entities and business logic calculations to the App layer through domain service (Domain Service) and domain object (Domain Entity) methods. The domain is the core of the application and does not depend on any other layers. At the same time, the domain layer will have a facade layer. When the domain service has external call dependencies, control inversion is achieved by defining the facade interface.

3. Adapter layer

Responsible for adaptation and integration with external systems or services, including communication, data caching, interface adaptation and other functions.

In addition, it is emphasized that RPC consumer calls are placed at the adapter layer. The adapter layer focuses on integration and adaptation with external systems, converting the interface and data format of the external system into a form that the application can understand and process. Placing RPC calls at the adapter layer can better decouple the technical details related to external systems from the application's business logic and domain objects, improving the scalability and maintainability of the application.

For all outbound adaptation layers, inversion of control needs to be implemented by implementing the facade interface.

4. Infrastructure layer

Responsible for providing the infrastructure that supports application operation, including implementation related to specific technologies. The infrastructure layer usually includes code that interacts with databases, message queues, caches, external services, etc., as well as some common tool classes and configurations, including filter and other implementations.

The relationship between the infrastructure layer and the adapter layer is:

  1. The infrastructure layer provides implementation related to specific technologies, such as database access, message queue connections, cache operations, etc. The adapter layer can use the functionality provided by the infrastructure layer to interact with external systems.
  2. The adapter layer uses the adapter pattern or a similar mechanism to convert the interface and data format of the external system into a form that the application can understand and process. The adapter layer is also responsible for forwarding application requests to the infrastructure layer for specific operations.
  3. The infrastructure layer and adapter layer work together to enable the application to integrate with external systems and decouple the technical details related to the external system from the application's business logic and domain objects. This enables application scalability, maintainability, and testability.

For some without complex logic, the upstream can also directly remove the infrastructure layer without necessarily going through the Adapter layer.

Scaffolding implementation practice

The above is mainly a theoretical introduction. Based on the above explanation, in practice, I built two sets of Java scaffolding with layered architecture. Specifically, it is divided into single module version and multi-module version. For microservice systems, if your business complexity for each service is not high, it is recommended to use a single module version; if you are a single application with complex business scenarios, it is recommended to use a multi-module version.

1. Single module scaffolding

--root
    --application: 应用层是程序的入口,整合和组合domain提供的能力。
        --rpc: JSF provider对外提供的接口实现
        --controller: springMVC提供的controller
        --listener: MQ消息监听器
        --task: 调度任务
        --translate: 将内部的BO映射为外部的VO/Entity
        --model: VO对象
    --adapter: 适配器层
       --rpc: JSF consumer,外部服务
       --mq: 消息队列sender模块
       --translate: 将外部数据结构映射为内部的DTO/BO
    --domain: 领域层
       --service: 领域服务可以按照自己情况灵活设计
       --facotry: 工厂
       --event/command: 事件驱动
       --model: 对象和实体
       --translate: 对象实体映射转换
    --infrastructure:
       --repository: 持久化层,包括db模型,sql读写等
       --cache: Redis缓存读写
       --producer: MQ消息生成,即发送MQ消息。
       --config: 配置信息,例如ducc配置、数据库、缓存配置等
       --translate: 将存储层的数据结构PO映射为内部的BO
       --utils: 工具集合
    --common: 公共层
       --exception: 主要分为业务异常和系统异常。系统异常需要研发处理。业务异常需要具备监控能力。
       --utils: 工具类
       --enums: 枚举类
       --common: 全局公共常量池
    --worker: 异步服务
    --client: JSF SDK

The maven private server pull script is as follows:

The single module version maven private server pull script is as follows:

mvn archetype:generate \
            -DarchetypeGroupId=com.jd.magnus \
            -DarchetypeArtifactId=magnus-single-archetype \
            -DarchetypeVersion=1.0.0-SNAPSHOT \
            -DinteractiveMode=false \
            -DarchetypeCatalog=remote \
            -Dversion=1.0.0-SNAPSHOT \
            -DgroupId=com.jdl.sps \
            -DartifactId=bff-single-demo1

2. Multi-module scaffolding

Here is a suggestion. In the multi-module version, because it is a complex single application, it is recommended to unpack it internally. Each layer can also perform unpacking operations based on different domain scenarios. The hierarchical structure is the same in each scenario. As shown in the figure below, there are two business scenarios in the app layer, including products and orders:



The multi-module version Maven private server pull script is as follows:

mvn archetype:generate \
            -DarchetypeGroupId=com.jd.magnus \
            -DarchetypeArtifactId=magnus-multi-ddd-archetype \
            -DarchetypeVersion=1.0.0-SNAPSHOT \
            -DinteractiveMode=false \
            -DarchetypeCatalog=remote \
            -Dversion=1.0.0-SNAPSHOT \
            -DgroupId=com.jdl.sps \
            -DartifactId=bff-demo1

summary

This framework combines DDD thinking and hexagonal architecture thinking, but the scaffolding will not limit everyone's ability and performance.

If you are proficient in DDD, you can write your code using the standard congestion model and subdomain splitting mode at the domain layer; if you are proficient in MVC, the framework can also be simplified to the familiar MVC development model. Model processing can also be handled flexibly, allowing for no over-design and multiple encapsulation of objects without affecting the overall code architecture, and encouraging agile iteration and regular refactoring.

But there is a core idea that needs to be kept in mind:

We try to ensure that our code development complies with the opening and closing principle, and can iterate new functions by adding classes and methods. We should try our best to avoid frequent modifications of a certain method or class, and ensure high cohesion between packages. Low coupling . Because the core of DDD thinking is the splitting of subdomains and the reasonable use of design patterns.

Author: JD Logistics Zhao Yongping

Source: JD Cloud Developer Community Ziyuanqishuo Tech Please indicate the source when reprinting

Alibaba Cloud suffered a serious failure and all products were affected (restored). Tumblr cooled down the Russian operating system Aurora OS 5.0. New UI unveiled Delphi 12 & C++ Builder 12, RAD Studio 12. Many Internet companies urgently recruit Hongmeng programmers. UNIX time is about to enter the 1.7 billion era (already entered). Meituan recruits troops and plans to develop the Hongmeng system App. Amazon develops a Linux-based operating system to get rid of Android's dependence on .NET 8 on Linux. The independent size is reduced by 50%. FFmpeg 6.1 "Heaviside" is released
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4090830/blog/10142674