业务|如何从0到1实践DDD( 四 )


建议的聚合设计原则:

  1. 在一致性边界之内确保不变性:聚合用来封装真正的不变性,而不是简单地将对象组合在一起。聚合内有一套不变的业务规则,各实体和值对象按照统一的业务规则运行,实现对象数据的一致性。
  2. 设计小聚合:如果聚合聚合包含过多的实体,会提高管理实体的复杂性,高频操作下容易并发冲突,降低了系统的性能。
  3. 在边界之外使用最终一致性:不同的聚合之间不要求强一致性,保证最终一致性。一次事务操作中,只修改一个聚合实例,如果需要修改多个实例,可以考虑通过异步的方式保证最终一致性。
3)领域服务
领域服务的定义:领域中的服务表示一个无状态的操作,它用于实现特定于某个领域的任务。当某个操作不适合放在聚合(实体)或值对像上时,最好的方式便是使用领域服务。
举个例子,在一个路线导航的项目中,“路线”可能是其中的一个实体,如果业务中有“推荐路线上相关的美食”这样一个功能,那我们会想,这个功能应该归给哪个领域对象,给“路线”实体吗?有点不合适,应该路线本身关注的是起终点,时间人物等。
此时可以将其这个功能归为领域服务,它是一个路线状态无关的服务,输入路线各个节点,来得到沿路的各种美食。当然,要注意不要过度地使用领域服务,因为这很可能导致你把实体的行为都放在里面了,实体本身都变成了一些只有getter和setter的“贫血模型”。
4)领域事件
领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。
领域事件含义很广泛,可以是业务流程的一个步骤,也可以是一个事件发生后触发的后续动作,缴费完成之后,触发短信通知;上面在设计聚合的时候,我们提到一个原则:在边界之外使用最终一致性,一次事务最多只能更改一个聚合的状态。如果一次业务操作涉及多个聚合状态的更改,应通过领域事件,达到最终一致性。
实际上是通过事件驱动的这种异步方式,对系统进行解耦。当然,如果你觉得某两个步骤,业务流程上不允许是不一致的,那就得重新考虑将其归在同个聚合中了。
4. 业务实践我们以增值运营服务上下文为例,根据上面的理解,结合业务实际,得到以下模型:
业务|如何从0到1实践DDD
文章插图
其中增值产品是其中的一个聚合根,通过该聚合根进行各种领域操作。海报缩略图是其中的一个领域服务,通过输入产品素材中的海报url,来得到一个海报的缩略图。
四、工程实践传统的三层架构和DDD的分层结构:业务|如何从0到1实践DDD
文章插图
在《领域驱动设计——软件核心复杂性的应对之道》一书中,Eric提出了这样的一种分层结构,将整个系统划分为四层:用户接口层、应用层、领域层和基础设施层。
用户接口层:用户接口层负责向用户显示信息和解释用户指令。
应用层:应用层相对来说是较“薄”的一层,主要是部署了应用服务。应用服务的实现中,它负责编排和转发下一层的领域层的接口,将要实现的功能委托给一个或多个领域对象来实现,本身只负责处理业务用例的执行顺序以及结果的拼装。
领域层:领域层是比较“厚”的一层,它包含聚合根、实体、值对象、领域服务等领域模型中的领域对象,实现了核心的业务逻辑。领域层和应用层的职责看起来有点模糊。