DDD 领域驱动设计

DDD的核心目的是为“高内聚,低耦合”提供一个可行办法。
微服务架构更强调从业务维度去做分治来应对系统复杂度,而DDD也是同样的着重业务视角。 如果两者在追求的目标(业务维度)达到了上下文的统一,那么在具体做法上有什么联系和不同呢?
我们将架构设计活动精简为以下三个层面:

业务架构——根据业务需求设计业务模块及其关系
系统架构——设计系统和子系统的模块
技术架构——决定采用的技术及框架

我们将通过上文提到的抽奖平台,来详细介绍我们如何通过DDD来解构一个中型的基于微服务架构的系统,从而做到系统的高内聚、低耦合。

首先看下抽奖系统的大致需求: 运营——可以配置一个抽奖活动,该活动面向一个特定的用户群体,并针对一个用户群体发放一批不同类型的奖品(优惠券,激活码,实物奖品等)。 用户-通过活动页面参与不同类型的抽奖活动。

设计领域模型的一般步骤如下:
	根据需求划分出初步的领域和限界上下文,以及上下文之间的关系;
	进一步分析每个上下文内部,识别出哪些是实体,哪些是值对象;
	对实体、值对象进行关联和聚合,划分出聚合的范畴和聚合根;
	为聚合根设计仓储,并思考实体或值对象的创建方式;
	在工程中实践领域模型,并在实践中检验模型的合理性,倒推模型中不足的地方并重构。

https://tech.meituan.com/2017/12/22/ddd-in-practice.html

	战略建模
	领域
	限界上下文
	划分限界上下文
		一个由显示边界限定的特定职责。领域模型便存在于这个边界之内。在边界内,每一个模型概念,包括它的属性和操作,都具有特殊的含义。
		我们的实践是,考虑产品所讲的通用语言,从中提取一些术语称之为概念对象,寻找对象之间的联系;
		或者从需求里提取一些动词,观察动词和对象之间的关系;我们将紧耦合的各自圈在一起,观察他们内在的联系,
		从而形成对应的界限上下文。形成之后,我们可以尝试用语言来描述下界限上下文的职责,看它是否清晰、准确、简洁和完整。
		简言之,限界上下文应该从需求出发,按领域划分。
	上下文映射图
		任何组织在设计一套系统(广义概念上的系统)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致。
		限界上下文之间的映射关系
			合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
			共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
			客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
			遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
			防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
			开放主机服务(Open Host Service):定义一种协议来让其他上下文来对本上下文进行访问。
			发布语言(Published Language):通常与OHS一起使用,用于定义开放主机的协议。
			大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
			另谋他路(SeparateWay):两个完全没有任何联系的上下文。
		通过上下文映射关系,我们明确的限制了限界上下文的耦合性,即在抽奖平台中,
		无论是上下文内部交互(合作关系)还是与外部上下文交互(防腐层),耦合度都限定在数据耦合(Data Coupling)的层级。
	战术建模——细化上下文
		实体
			当一个对象由其标识(而不是属性)区分时,这种对象称为实体(Entity)
				例:最简单的,公安系统的身份信息录入,对于人的模拟,即认为是实体,因为每个人是独一无二的,
				且其具有唯一标识(如公安系统分发的身份证号码)。
		值对象
			当一个对象用于对事务进行描述而没有唯一标识时,它被称作值对象(Value Object)。
				例:比如颜色信息,我们只需要知道{“name”:“黑色”,”css”:“#000000”}这样的值信息就能够满足要求了,
				这避免了我们对标识追踪带来的系统复杂性
			具有不变性、相等性和可替换性。
			谨慎使用值对象
		聚合根
			Aggregate(聚合)是一组相关对象的集合,作为一个整体被外界访问,聚合根(Aggregate Root)是这个聚合的根节点。
			聚合是一个非常重要的概念,核心领域往往都需要用聚合来表达。其次,聚合在技术上有非常高的价值,可以指导详细设计。
			聚合由根实体,值对象和实体组成。
		领域服务 一些重要的领域行为或操作,可以归类为领域服务。它既不是实体,也不是值对象的范畴。
		领域事件 领域事件是对领域内发生的活动进行的建模。
	DDD工程实现
		模块	前文提到,领域驱动要解决的一个重要的问题,就是解决对象的贫血问题。
			这里我们用之前定义的抽奖(DrawLottery)聚合根和奖池(AwardPool)值对象来具体说明。
		领域对象	前文提到,领域驱动要解决的一个重要的问题,就是解决对象的贫血问题。
			这里我们用之前定义的抽奖(DrawLottery)聚合根和奖池(AwardPool)值对象来具体说明。
		资源库	领域对象需要资源存储,存储的手段可以是多样化的,常见的无非是数据库,分布式缓存,本地缓存等。
			资源库(Repository)的作用,
			就是对领域的存储和访问进行统一管理的对象。在抽奖平台中,我们是通过如下的方式组织资源库的。
		防腐层	亦称适配层。在一个上下文中,有时需要对外部上下文进行访问,通常会引入防腐层的概念来对外部上下文的访问进行一次转义。
		领域服务
			上文中,我们将领域行为封装到领域对象中,将资源管理行为封装到资源库中,将外部上下文的交互行为封装到防腐层中。
			此时,我们再回过头来看领域服务时,能够发现领域服务本身所承载的职责也就更加清晰了,
			即就是通过串联领域对象、资源库和防腐层等一系列领域内的对象的行为,对其他上下文提供交互的接口。
		数据流转
			首先领域的开放服务通过信息传输对象(DTO)来完成与外界的数据交互;
			在领域内部,我们通过领域对象(DO)作为领域内部的数据和行为载体;
			在资源库内部,我们沿袭了原有的数据库持久化对象(PO)进行数据库资源的交互。
			同时,DTO与DO的转换发生在领域服务内,DO与PO的转换发生在资源库内。
		上下文集成
			常见的手段包括开放领域服务接口、开放HTTP服务以及消息发布-订阅机制。
		分离领域
posted on 2021-07-17 19:35  弘航  阅读(124)  评论(0)    收藏  举报