DDD actual combat sharing - Message Center

Keywords: Go

What problem does DDD solve / why use DDD

You can write your answers in the comments area

















DDD overall process (source: ThoughtWorks)

v1

v2

The biggest difference is that the event storm in the first step is replaced by the identification core domain of strategic design. Personally, I don't think it's suitable to discuss the core domain in advance when I'm not familiar with the new business, because I don't have enough information, all rely on speculation, and too much discussion in the early stage wastes time.

Personal understanding of DDD process

  1. early stage
    • Value, pain point, demand
  2. Event storm
    • Identify events
    • command
    • Domain NOUN
      1. Business modeling / strategic design (development and business modeling)
    • Partition sub domain / core domain
    • Bounded context
    • Establish business model
      1. Model design / tactical design (modeling between development)
    • model design
    • api design
    • Layered architecture
    • Database design
    • Code writing
    • release

The output of the upper layer is the input of the lower layer.

DDD tactical design related concepts

concept explain
Bounded context A microservice has multiple bound contexts, which can be simply understood as modules, packages and namespaces. For example, there may be category aggregation in context a and category aggregation in context B. They are all called category, but they have different meanings
polymerization It is also a boundary that divides entity and value objects into aggregations and defines boundaries around aggregations
Aggregate root The primary entity in an aggregation can be composed of multiple entities and value objects. An aggregation has only one aggregation root
entity The aggregation root is an entity. An entity is not necessarily an aggregation root. An entity is an abstraction of multiple table models (it can be equivalent po or composed of multiple po)
Value object Object without ID (unique flag)
Domain object Including: aggregation, aggregation root, entity, value object and domain event. All objects in the domain layer are called domain objects
DO Domain Object, ibid., Domain Object. Location: domain layer
DTO Data Transfer Object. Significance of existence: the circulation object of upstream and downstream services. Location: interface layer
PB Proto Buffer, meaning of existence: the circulation object of GRPC upstream and downstream services is equivalent to DTO here. Location: interface layer
PO Persistence Object, persistent object. Significance: equivalent data table model. Location: infrastructure layer
VO View Object. Existential meaning: a kind of domain object, which is mainly used for query. Location: domain layer
Value Object Value object, location: domain layer
BO Business Object. Existential significance: a container for assembling two or more domain objects. Location: application layer

DDD four layer structure

arrangement duty
Interface layer / presentation layer Be responsible for presenting information to users and interpreting user commands
Interface layer / presentation layer Be responsible for presenting information to users and interpreting user commands
application layer A thin layer used to choreograph one or more domain services and return domain objects or business objects to the interface layer
Domain layer The core layer is responsible for writing business logic. Operations such as database persistence are delegated to the infrastructure layer
Infrastructure layer Implementation of business object persistence; Call downstream services

Circulation objects at all levels of DDD (current situation of message center)


DDD code directory

  • server interface layer
  • application layer
  • Domain domain layer
  • infra infrastructure layer

    A microservice has multiple bound contexts. The lower directory of the domain layer refers to the division of the bound context. The lower level directories of other infra/persistent, server and application layers are subcontracted by module. The design up and down by module + gauge is a compromise scheme to solve the landing cost of four-tier directory design in each context.
    The advantage of subcontracting by module is to solve domain noun conflicts. For example, there may be category aggregation in context A and category aggregation in context B.

Granularity division:
Realm > subdomain > bounded context > aggregate > aggregate root / entity / value object

Go GRPC DDD framework

Go GRPC DDD framework directory description

|-- application                                 //application layer
|   |-- directories                                 //Module (technical perspective), here refers to the developer directory module
|   |   |-- assembler                                   //Application layer object translator
|   |   |   |-- category.go
|   |   |   `-- developer_dir.go
|   |   `-- developer_dir_app.go                        //Developer directory app 
|   |-- example                                     //Module (technical perspective), example module
|   |   `-- example_app.go
|   |-- module3                                     //Module (technical perspective), example module 3
|   |   `-- xxxx_app.go
|   |-- module4                                     //Module (technical perspective), example module 4
|   |   `-- xxxx_app.go
|   `-- module5                                     //Module (technical perspective), example module 5
|       `-- xxxx_app.go
|-- build.yaml
|-- domain                                      //Domain layer
|   |-- directories                                 //Boundary context (domain perspective), which refers to the boundary context of the developer directory
|   |   |-- aggregate3                                  //Aggregation, example aggregate3
|   |   |-- category                                    //Aggregation, classification
|   |   |   |-- category_repo.go                            //Classification aggregation warehousing interface
|   |   |   |-- category_service.go                         //Classification aggregation service
|   |   |   |-- entity                                      //entity
|   |   |   |-- event                                       //event
|   |   |   `-- vo                                          //form object 
|   |   `-- developer_dir                               //Aggregation, developer directory aggregation
|   |       |-- developer_dir_repo.go
|   |       |-- developer_dir_service.go
|   |       |-- entity
|   |       |-- event
|   |       `-- vo
|   |-- example                                     //Bounded context (domain perspective), example context
|   |   |-- aggregate1
|   |   |-- aggregate2
|   |   `-- example
|   |       |-- entity
|   |       |-- event
|   |       |-- example_repo.go
|   |       |-- example_service.go
|   |       `-- vo
|   |-- ctx1                                        //Bounded context (domain perspective), example context 1
|   |   `-- aggregate1
|   |       |-- aggregate1_repo.go
|   |       |-- aggregate1_service.go
|   |       |-- entity
|   |       |-- event
|   |       `-- vo
|   |-- ctx2
|   |   |-- aggregate1
|   |   `-- aggregate2
|-- go.mod
|-- go.sum
|-- golangci.yml
|-- infra                                       //Infrastructure layer
|   |-- common
|   |   |-- authorize.go
|   |   |-- jwt.go
|   |   |-- page_info.go
|   |   |-- queue
|   |   |   |-- consumer.go
|   |   |   |-- etcd.go
|   |   |   |-- message.go
|   |   |   |-- mns_client.go
|   |   |   |-- queue_producer.go
|   |   |   |-- server.go
|   |   |   |-- setup.go
|   |   |   `-- topic_producer.go
|   |   |-- rpc_client
|   |   |   `-- rpc_client.go
|   |   `-- tree.go
|   |-- di
|   |   |-- developer_dir.go
|   |   `-- example.go
|   |-- persistent                              //Persistence layer
|   |   |-- directories                             //modular
|   |   |   |-- assembler                               //Object Converter
|   |   |   `-- repsitory                               //Warehouse realization
|   |   |-- example
|   |   |   `-- repsitory
|   |   |-- module3
|   |   |   `-- repsitory
|   |   `-- module4
|   |       `-- repsitory
|   |-- pkg
|   |   |-- businesscode
|   |   |   `-- businesscode.go
|   |   |-- constant
|   |   |   `-- common.go
|   |   |-- errcode
|   |   |   |-- common_errcode.go
|   |   |   `-- custom_errcode.go
|   |   `-- utils
|   |       |-- common.go
|   |       `-- db_insert_build.go
|   |-- po                                      //Persistent object, data table model
|   |   |-- oa_developer_dir.go
|   |   |-- oa_developer_dir_category.go
|   |   |-- oa_developer_dir_suppliers.go
|   |   `-- oa_developer_dir_user_down.go
|   |-- remote                                  //Remote call
|   |   `-- micro_basic_service
|   |       `-- id_generation_service.go
|   `-- startup
|       |-- config.go
|       |-- mq_register.go
|       |-- register.go
|       `-- vars.go
|-- main.go
|-- micro-msgcenter-mng-service
|-- proto                                       //pb protocol
|   |-- micro_msgcenter_mng_service_proto
|   |   `-- micro-msgcenter-mng-service
|   |       |-- directories                             //modular
|   |       |-- example                                 //modular
|   |       `-- module3
|   |-- swagger_json.go
|   
|-- server                                      //Interface layer      
|   |-- directories                                 //modular
|   |   `-- developer_dir.go
|   |-- example
|   |   `-- example.go
|   |-- module3
|   `-- module4
|-- xxx.yaml
`-- vendor

PHP BFF directory structure

proto directory


BFF is divided into modules according to clearance context, and proto is also subcontracted according to clearance context

Case explanation

Message center business model divided according to strategic design


The implementation of product context is analyzed below.

Tactical design - model design in product context

api design

BFF

Interface name Module (gauge context) Controller (aggregate) Behavior (event) url
Get product application product product get-applications micro-msgcenter-mng-api.cc/product/...
Get application scenarios product app get-scenes micro-msgcenter-mng-api.cc/product/...
Add & modify application scenarios product app set-scenes micro-msgcenter-mng-api.cc/product/...

GRPC

grpc interface name Package name (microservice name underscore. Bounding context) rpc Service name (aggregate Service) rpc method (event / behavior) Service path
Get product application micro_msgcenter_mng_service.product ProductService GetApplications micro_msgcenter_mng_service.product.ProductService/GetApplications
Get application scenarios micro_msgcenter_mng_service.app AppService GetScenes micro_msgcenter_mng_service.app.AppService/GetScenes
Add & modify application scenarios micro_msgcenter_mng_service.app AppService SetScenes micro_msgcenter_mng_service.app.AppService/SetScenes

GRPC-Gateway

Interface name Module (gauge context) polymerization Behavior (event) url
Get product application product product get-applications micro-msgcenter-mng-service/product/product/get-applications
Get application scenarios product app get-scenes micro-msgcenter-mng-service/product/app/get-scenes
Add & modify application scenarios product app set-scenes micro-msgcenter-mng-service/product/app/set-scenes

At the beginning of the design, it is not recommended that the boundary context name and the aggregation name have the same name;
The interface path is defined according to "gauge context / aggregation / behavior".

BFF obtains product application APIDOC definition

 /**
    * @api {get} /product/product/get-applications Get product application
    * @apiDescription Get product application
    * @apiSampleRequest http://micro-msgcenter-mng-api.cc/product/product/get-applications
    * @apiVersion 2.0.0
    * @apiName get-applications
    * @apiGroup /product/product
    * @apiSuccess {Boolean} success         Return status
    * @apiSuccess {String} message         Return message content
    * @apiSuccess {Object} data             Result set
    * @apiSuccessExample {json} Success-Response:
    * HTTP/1.1 200 OK
    * {
        "success": true,
        "message": "",
        "error_code": "",
        "data": [
            {
                "product_code": "product1",
                "product_name": "Product 1 ",
                "app": [
                    {
                        "app_id": "1",
                        "app_name": "app1",
                    },
                    {
                        "app_id": "2",
                        "app_name": "app2",
                    }
                ]
            }
        ]
    }
    */

As you can see, this interface requires data from product aggregation and application aggregation.
Because the combined object cannot belong to either product entity or application entity, it is a combination of two domain objects. There needs to be an object to load. This object is BO (business object).

Compared with microservices, microservices are only responsible for the fields within the microservices, and aggregation is only responsible for the aggregated entities.
The core of DDD is clear boundary division.

The following figure shows the service orchestration of the application layer

Aggregation design of applications and scenarios



The method of golang inheritance is used to realize entity definition and reduce the cumbersome definition of structure.
Different from the traditional table model, DDD entity is the abstraction of table model. An entity may be composed of multiple table models. Of course, these multiple table models belong to an aggregation. In this example, the application and scenario constitute an entity. The application is the aggregation root (primary entity), the scenario is the entity, and the aggregation root is the representative of communicating with external objects. The business operations of non primary entities need to be completed through the aggregation root. If you want to modify or view the application scenario, you need to operate through application aggregation:

Get scene: AppService.GetScenes(ctx, appId)
// app = *entity.App
 Set the scene: AppService.SetScenes(ctx, app)

Instead of getting a scene service to operate

Get scene: ScenesService.GetScenes(ctx, sceneId)
// scene= *entity.Scene
 Set the scene: ScenesService.SetScenes(ctx, scene)

Aggregation concept reference article: Deeply understand the aggregation mode of DDD

Circulation objects at all levels of DDD (recommended version)

problem

affair

other

What thinking models can be learned from DDD

Hierarchical thinking

"Any problem in the computer field can be solved by adding an indirect middle layer"

! [insert picture description here]

Classified thinking

For many problems, how to reduce the number of problems to be solved can be classified.
For example:

  • How to make a hundred million
  • How to keep healthy
  • How to improve expression ability
  • How to realize wealth freedom
  • How to find a girlfriend
  • How to have a happy family
  • How to work efficiently
  • How to communicate effectively
  • How to take care of children
  • How to improve your writing skills
  • What kind of exercise is the healthiest
  • How to run

Problem domain classification

It can also be more abstract. The higher the level of abstraction, the broader the field of vision, and the more problems to consider.

Boundary thinking

Example: the company's organizational structure is divided into departments / groups

Posted by codecontractor on Fri, 17 Sep 2021 01:04:26 -0700