【Day 07】领域驱动设计的战术设计(Tactical Design)

前言

上一篇我们讨论DDD的战略设计,说明系统范围如何切割成多个领域(Domain)、子领域(Sub-Domain),完成後,接着进行战术设计,将实体进一步分类,并订定技术架构,提供服务以操作这些实体。

DDD 战术设计

Eric Evans 描述DDD的工作范围如下,其中上半部为战术设计,下半部为战略设计:
https://ithelp.ithome.com.tw/upload/images/20211010/20001976JHZu6LMlw2.png
图一. DDD 战术设计

依照上图,战略设计(Model-driven design)要进行的工作如下:

  1. 实体(Entity):将领域内的各项实体识别出来。
  2. 值物件(Value Object):表达实体的状态(State)及计算(Computation)。
  3. 领域事件(Domain Event):列出所有影响实体的事件,说明实体变化及状态。
  4. 聚合(Aggregate):将相关的实体封装为聚合。
  5. 设计模式(Design Patterns):建立工厂(Factory)、仓储设计模式(Repository),以利於产生物件及存取。
  6. 服务(Service):将模型包装成服务,变成API。

聚合(Aggregate)

为达到『高内聚、低耦合』(High conhesion、Low Coupling)的设计原则,会将各个实体归类成一个个的聚合,例如客户、订单(保单)、产品...等,客户聚合包括客户主体、多个帐户实体、多个分公司地址,其中客户主体称为聚合根(Aggregate Root),它具有唯一的识别栏位(ID),可以存取单一实例(instance),聚合就像是肉粽串,而聚合根就是草绳的头,往上提就可以把聚合内所有的实体都抓起来,因此,聚合根是一个带有业务规则的实体,是对外沟通的窗口。

因此,我们会将一个领域或子领域细分为多个聚合,每个聚合有唯一的聚合根,秉持『高内聚、低耦合』的原则,尽量减少聚合间的连结。

实体(Entity) vs. 值物件(Value Object)

值物件是表达实体的状态(State),没有识别的Id,例如订单上客户的地址,它是订购当时客户的地址,可能不是最新的,或是订单上的总价或折扣,只是计算栏位,是一个快照(Snapshot)的概念,因此,一个庞大的实体尽量能拆成多个值物件,会使实体变得更容易维护,因为值物件是不可修改的(Immutable),要嘛整个删除或是重新建立,例如下图。
https://ithelp.ithome.com.tw/upload/images/20211010/20001976DRKoMTzJaE.jpg
图二. 实体(Entity) vs. 值物件(Value Object),信用报告含多个值物件

Domain Object vs. Persistent Object

我们使用各种 ORM、MVC 或 MVVM 架构撰写应用程序时,系统会要求我们建立类别,与资料库的资料表/栏位对应,这就是所谓的Persistent Object(PO),类别内只有属性,没有方法,称为POJO(Java)或POCO(C#),会让人误以为这就是实体,依 DDD 的设计原则来看,这是不好的『贫血模型』(Anemic Domain Model),它会使操作物件的方法全部写在类别外的程序逻辑中,违反物件导向设计原则(OOP)、单一职责设计原则(Solid),使程序逻辑全部搅在一起,难以维护,因此,我们应该在Persistent Object上,重新组织一层 Domain Object,将相关的PO连结在一起,并且赋予相关行为的描述,即充血模型,业务逻辑应放类别里面,例如MVVM的View Model就是Domain Object(DO),它可以是画面(View)的资料来源,也可能是API的输入/输出(REST、WSDL)、网路传输的资料内容(Data Transfer Object, DTO)。

在程序开发时 DO 与 PO 的互转非常频繁,笔者使用C#开发程序时,就常使用 AutoMapper 函数库,进行 DO 与 PO 的转换。譬如https://ithelp.ithome.com.tw/upload/images/20211010/20001976LoEWQUtvHD.png,从请购单、采购单、到货通知单、验收单,多张请购单可能并成一张采购单,多张采购单可能一次到货,也可能分批到货,验收时也是如此,这些单据如果都是一个物件,每个物件都会影响其他物件的状态及内容。

Design Pattern

DDD 建议引用各种设计模式,提高生产力,例如 Repository/Factory简化物件产生/共通方法操作,Adapter方便模组挂载,PPublish/Subscribe处理事件的传送/接收,目前各种语言都可以找到相关的框架(Framework)或函数库,可以直接套用,後续我们就来看看Python相关的套件。

结语

DDD 并没有严格规定进行的步骤,只有一些原则(Principle),每本书籍的作者各有领悟,利用上述的原则,自行订定详细的执行步骤,大部份都搭配Java框架,笔者推荐『中台架构与实现:基於 DDD 和微服务』一书的说明,不过,笔者并不喜欢Java繁复的架构,所以,想使用Python试试看,它又可以轻易的整合机器学习模型。


<<:  Day25 - this&Object Prototypes Ch3 Objects - Review

>>:  Day 25 - 影像、声音与影片的整合与拆解

## 第二十九课:自由练习

前言 就如同标题所讲的,今天就来自由练习吧。那今天我练习的主要会是在骨架的部分。对,过了这麽久依旧在...

TypeScript 能手养成之旅 Day 3 判断资料型别

前言 今天正式进入 TypeScript 内容及使用,我们首先会接触的就是 型别系统 。 型别系统设...

世界上最快乐的人 (3) 慈心与悲心

昨天上完 SIY 的课程後,实在是太累了,我想可能是因为有某部分的放松的关系,在阅读以下段落时,又觉...

display:block及display:inline 差别

display:block及display:inline 差别 每个不同tag都会对应不同预设值设...

CompTIA 220-1002 Dumps PDF with Actual 220-1002 Exam Questions

IT business is one of the most famous in the busin...