preface
DDD stands for domain-driven Design. It is derived from a highly influential book “Domain-Driven Design – Complexity in the Heart of Software” referring to dzj00 by Eric Evans, a leading modelling specialist. Domain-driven design — a solution to software core complexity). It was first widely used in traditional software architecture design.
In April, InfoQ released its trends report on software architecture and design. It can be seen from the report that micro-services and dome-driven design have become the mainstream trend of the software development industry. The author also understands that DDD has become the guiding ideology of most enterprises’ micro-services landing and construction in Taiwan.
(Photo: infoQ)
Isolation change and precipitation reuse
In the Internet era, at the initial stage of business system construction, the scene is usually simple and clear, and the agile iteration of business can be supported based on database table design +CRUD. Over time, scenarios and business logic became complex and customized, modules were coupled to each other, and systems became more and more bloated, often affecting all of them. Even with the seemingly simple logic of adding a field, just sorting out the impact on other function points and modules requires at least one veteran team member who is familiar with both the business and the code. Believe that a business system that has been in place for more than a year, its architecture and code are likely to be experiencing all of this and slowly beginning to decay.
The most classic example is the design of the following product class in the e-commerce system (the number of fields may be hundreds in reality), which does not conform to the architecture design principle of high cohesion and low coupling:
The product class is all-encompassing and knows everything about any field. Its responsibilities are not clear, the expectations of team members are not consistent in precipitation reuse, and the implementation posture may be strange; Logical changes in procurement, storage and distribution business fields may all require product modification. A highly cohesive system design needs to isolate changes as much as possible, so that the impact is minimal and controlled within a certain boundary.
DDD achieves decoupling and reuse by dividing the bounded context and dismantling the molecular domain:
The following image is from The Godfather of Software development: Martin Fowler. To be sure, to cope with increasingly complex business logic, replacing the data table model with a top-down domain aggregation model is the only way to truly achieve flexible scalability with business entities at the core:
Procedural scripting, which does not extend well;
Data table-oriented design, which focuses too much on data ignoring behavior, cannot be reused well.
This has led to a resurgence of DDD enthusiasm among systems enthusiasts who survived the dotcom bubble, hoping that DDD will help them regain confidence in building more sensible software architectures. But on the ground, thorns and difficulties vary. Now let’s introduce DDD’s landing practice in the field of JD DevOps project collaboration.
Apply DDD to componentization
Within JINGdong, there are two systems in the field of project collaboration that cover a particularly wide range of users (total users 8W+) : PMP and Xingyun.
PMP is a project management software more oriented to project managers, including project process management, requirements management, milestone management, task management, time management, cost management, OKR management, ROI verification and satisfaction scoring, etc. In terms of architecture design, PMP is a very large single application. Its front and back ends are not separated, all business logic is mixed together, and the number of project form fields reaches 100+. Over time and organizational change, scalability and maintainability was a disaster.
The initial positioning of Xingyun is agile collaborative software for R&D, including cross-department requirements management, agile iteration and task management, etc. With the widespread use of xing Yun, there is a growing call to integrate PMP functions into xing Yun.
At the same time, Xing Yun provides ToB services outside the company. There are so many different scenarios and businesses, both internal and external, that simply adding an if else mud ball just doesn’t work anymore. Under the new positioning and background, we must split the business logic into flexible components, so as to achieve reuse and logic precipitation; On the other hand, the logic of differentiation can be extended flexibly. There are huge challenges:
The middle arc in the figure above describes our DDD strategies and tactics to address business and technical challenges based on the principles we used when we split components (business independence, high cohesion, low coupling, data integrity, incremental).
Business Challenges
Both PMP and cloud have requirements management and task management. Are the requirements and tasks a concept? What are the relationships between projects, requirements, iterations, tasks, and so on? How to precipitate a clear set of reusable business components internally and externally?
DDD contains many concepts, including bounded context, aggregation, aggregate root, entity, value object, etc. This article will not focus on these details, but directly focus on the following issues:
1. Divide boundaries, identify domain objects or domain classes, and ensure their responsibilities are clear and pure; 2. Clear the association and dependence between domain classes, and define the invocation relationship and way.
Through domain analysis and modeling, a unified language is formed, and finally the whole project collaboration management is split into business domains with complete functions and clear business logic, such as project domain, task domain, engineering domain and so on. Each business domain provides explicit domain services externally, and a business domain can manage multiple business entities.
Technical challenges
After the division of the field, the ideal situation is that each field has a high degree of autonomy, reducing dependence, and even each field can be realized by different teams, each team focuses on the accumulation of the core capabilities of the field.
Finally, we came up with a componentized solution: according to the divided domains, the system was divided into business components (core subdomains) and base components (common and supporting subdomains), with the front and back ends of each component separated. That is, there will be the following front-end applications: requirements management, project management, defect management, use case management, etc. Back-end applications provide different domain services, which adopt hierarchical architecture (interface, Application, Domain, infrastructure). Basic components such as permission management, gateway services, and message services are sunk to maximize component reuse.
It is divided into service components according to the domain. For the system, it is provided to end users as a whole. But componentization means separation, so what are the synergistic challenges for the front-end and back-end applications of business components?
Challenges of business component front-end applications
To enable the parallel and independent evolution of service components, ideally, front-end applications must be independently compiled, packaged, and deployed, and finally integrated into a platform to present a unified UI style and consistent interactive experience.
This is what the industry refers to as microfront-end architecture: implementing an architectural style that combines many independently delivered front-end applications into a large whole and presents a single, complete product to the customer.
Finally, our Line cloud team landed a Jmodule micro front-end component framework.
Front-end applications register with the platform through the micro-front-end architecture and front-end component framework. The system layer implements component metadata management, static resources hot-loading during runtime and communication between components, and provides fully pluggable and configurable components for users. The specific principles and implementation will be developed in another chapter.
Challenges for business component back-end applications
At the beginning of the design of Xingyun, the back-end service adopts the micro-service architecture (using Spring Cloud Gateway, Eureka and other services to achieve service registration, gateway invocation, etc.), which is well matched with DDD. Within the core business components, domain services are organized in a classical hierarchical architecture (interface, Application, Domain, infrastructure).
Interface-user interface layer: Controller, restful interface invocation, Web UI, mobile UI, third-party services, etc. Apllication – Application layer: it provides various application functions for the presentation layer externally, and calls the domain layer (domain service) internally. The application layer is more like the strategy to realize a specific scene or the orchestration of the process. It collaborates services in multiple domains to achieve isolation of scenarios and services. Domain-domain layer: Is responsible for expressing business concepts, business behaviors, business states, and business rules. Domain model is located in this layer and is the core of business software. It provides a set of atomic services, and a rich OPEN API at this layer is a crucial step in achieving componentization; Infrastructure – Foundation layer: The layer that implements business and technology isolation. It generally includes network communication, database persistence, asynchronous message service, southbound gateway service and so on. This layer in the landing, can realize a variety of adaptor to compatible internal, external, multi-cloud heterogeneous middleware environment.
In addition to defining the boundaries of the internal layers of a component, you also need to clarify the calls and dependencies between components to further clarify the responsibilities of the component. The mapping between bounded contexts is defined in DDD accordingly:
2. A relationship in which two contexts work closely together; Client-supplier side: organized upstream and downstream dependencies between contexts; Follower: Downstream context can only blindly rely on upstream context; Separation: two contexts that have no connection at all; Shared kernels: models where two contexts are partially shared; Anticorrosion layer: One context interacts with another through some adaptation and transformation; Open hosting services: Define a protocol to allow other contexts to access this context; Event publishing Subscription: A protocol commonly used to define open hosting.
In terms of component calls and dependencies, we can use the above mapping concept to land.
For example, we have precipitated the project component and the task component. The following describes the service scenario to be implemented: When deleting a project, check whether the project has ongoing tasks. If no task is deleted, a message is displayed indicating that the project cannot be deleted. Based on the DDD mapping, the task is project-dependent, the task is upstream, and ideally it does not need to know the specific logical rules that the project business domain removes, while minimizing the impact of changes to the project business rules.
Therefore, when we landed, we eliminated the implementation mode on the left side of the figure — partnership (projects and tasks intercall each other in a network), but added an adaptation layer in the downstream project domain to isolate the impact of business changes on the upstream. At the same time, make sure the task layer logic is clean and clear, so that more components can reuse it.
conclusion
To sum up, this paper gives the guiding significance of DDD trend in the following aspects:
How do YOU precipitate clear reusable business components? How do YOU isolate the impact of changes between components on other components?
Stay tuned for
The practice of DDD plug-in implementation will be shared in the following chapters to solve the following problems:
How do you respond quickly to a wide variety of customization requirements while remaining uncorrupted?