接触DDD也有一段时间了,包括我们自己的项目就是遵循DDD设计的目录结构和代码结构,可惜团队中并没有相关的大佬能培训下这块。今天闲来无事就整理下自己的DDD笔记吧。
注:毕竟是整理自己的笔记,部分内容没有记录参考链接,见谅哈。而且仅限于自己的理解,有些错误的地方,欢迎大佬指正~
领域驱动设计分为两个阶段:
(1)以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型;
(2)由领域模型驱动软件设计,用代码来实现该领域模型;。
DDD主张工程团队必须与主题专家(SME)交谈,他们是领域内的专家。这样做的原因是SME拥有关于领域的知识,这些知识应该反映在软件中。想想看,如果我要做一个股票交易平台,作为一名工程师,我对这个领域的了解够不够去做一个好的股票交易平台?如果我能和沃伦·巴菲特谈谈这个领域,这个平台可能会好得多。
传统的mvc结构,在接到需求之后,我们可能会先设计mysql的数据表,然后根据表的字段去和业务场景进行匹配,是一种从下而上的设计思路。
而在DDD中,在接到需求之后,首先是需要进行讨论,明确需求以及对应的各种场景,划分需求的子域和限界上下文,乃至实体,值对象等。开发人员在对需求烂熟于心之后,开始从上而下的设计代码模型,最终实现需求。
看起来好像DDD比着传统的mvc要麻烦很多,是的,确实很麻烦。。。不过对于快速迭代或者复杂的大项目来说,遵循DDD可以让你的代码扩展性更强,高内聚低耦合的设计也能防止屎山的产生,可谓功在千秋了。
参考链接:mvc和DDD的区别
参考:美团高级技术专家:DDD 在旅游电商架构演进中的实践
这个ppt里面有关于设计DDD的具体流程,建议大家可以去看看,很仔细了。我们可以根据这张图了解下DDD的一个设计流程,从讨论到精炼出具体的模型,设计各种子域和限界上下文等等。
DDD主要分为两个部分,战略设计与战术设计,战略设计围绕微服务拆分,战术设计围绕微服务构建。
细节如图:
这里的领域指的是业务领域。
在领域不断划分的过程中,领域会细分为不同的子域,子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域。
核心域: 决定产品和公司核心竞争力的子域是核心域,它是业务成功的主要因素和公司的核心竞争力。
通用域: 没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域。
支撑域: 还有一种功能子域是必需的,但既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,它就是支撑域。
参考:DDD(领域驱动设计)系列主题:限界上下文
将限界上下文拆解为两个词:限界和上下文。限界就是领域的边界,而上下文则是语义环境。 在很多文章中都说限界上下文就是我们的微服务,这种说法也没错,只不过限界上下文也可以是子域中的一个概念。
1)微服务
在DDD战略设计阶段识别出来的“限界上下文”,会作为战术设计阶段微服务设计和拆分的主要依据,理论上“限界上下文”的边界是就微服务的物理部署边界。
2)同一个服务内
一个服务内,我们除了限定大的领域之外,还会有子域的概念。一个领域相当于一个问题域,领域拆分为子域的过程就是大问题拆分为小问题的过程。
那么各个子域之间的边界,也可以是限界上下文,保证各个子域内的聚合,语义的唯一性。
防腐层(ACL):DDD(Eric Evans)中引入的模式, 用于隔离两个系统, 允许两个系统之间在不知道对方领域知识的情况下进行集成。
1)服务之间的防腐层
1、在架构层面,通过引入防腐层有效隔离限界上下文之间的耦合;
2、防腐层同时还可以扮演适配器、调停者、外观(Facade)等角色;
3、防腐层往往属于下游限界上下文,用以隔绝上游限界上下文可能发生的变化;
2)同一个服务中的防腐层
比如下单服务,里面可能还包含商品,订单,结算支付等子域。为了保持各个子域的独立性,定义防腐层,对各个子域之间的调用做一层转换即可。
实体一般对应业务对象,它具有业务属性和业务行为;而值对象主要是属性集合,对实体的状态和特征进行描述。但实体和值对象都只是个体化的对象,它们的行为表现出来的是个体的能力。
举例:人,也就是业务类型本身
聚合就是由业务和逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化。
聚合中包含实体,实体的生命周期由聚合根管理。聚合之间通过聚合根关联引用,如果需要访问其他聚合的实体,先访问聚合根,再导航到聚合内部的实体。
举例:社团,组织,部门
如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。
聚合根之间以ID导航,OrderItem里持有ProductID而不是Product的reference。使用的时候由ProductID从ProductRepository里load出来。这在DDD里叫失联模型(disconnected model)
主要是配合基础设施使用。基础设施可能是数据库,文件或者内存对象等。仓储层是对于crud
做了一层抽象。例如解耦业务和mysql
之前的强耦合关系,
通过调用仓储去实现持久化或者查询操作,不用去关心具体的实现。
参考:DDD系列文章
├─catalog // 商品目录子域
│ ├─application
│ ├─domain
│ ├─infrastructure
│ └─presentation
├─order // 订单子域
│ ├─application
│ ├─domain
│ ├─infrastructure
│ └─presentation
└─store // 商家子域
├─application
├─domain
├─infrastructure
└─presentation
├─catalog // 商品目录子域
│ ├─application // 应用层
│ │ ├─brand
│ │ ├─category
│ │ ├─collection
│ │ └─product
│ ├─domain // 领域层
│ │ ├─brand // 商品品牌模块
│ │ ├─category // 商品类目模块
│ │ ├─collection // 商品集合模块
│ │ └─product // 商品模块
│ ├─infrastructure // 基础设施层
│ │ └─persistent // 持久化
│ │ ├─jpa
│ │ ├─mybatis
│ │ └─redis
│ └─presentation // 表现层
│ ├─graphql
│ ├─grpc
│ ├─rest
│ ├─view
│ └─websocket
└─order
├─application
│ ├─dispute
│ ├─review
│ ├─shipping
│ └─source
├─domain
│ ├─dispute
│ ├─review
│ ├─shipping
│ └─source
├─infrastructure
└─presentation
end