领域驱动设计(1)--概念与生命周期

时间:2022-10-28 19:08:42

注:这本书曾经根本看不进去,但是在别人的提纲挈领的讲解下,突然觉得这一块可以进行一些阅读。

一、主题

领域模型就是对于业务的概念、概念间的关系以及概念本质的认知。

为了控制话题,目前只讨论领域模型或者领域对象的生命周期

二、分论

1.背景:

领域相关的大体分为四个主题,统一设计语言;分层架构与分离模型;DDD设计要素;领域模型的根与边界上下文。

这个出现是为了解决一个问题:曾经的软件开发模式有一点点小问题。不过如果一个软件的生命周期只有一两年,那么可以绕行。

因为还没等到软件复杂度上来,软件的寿命已经结束了。那么考虑领域模型没有现时的商业需要,只剩下内在的艺术追求了

2.比较的对象

短平快的商业需求,直接催生了测试驱动测试的开发模式或者敏捷开发,

例子:产品根据业务要求提出用户需求,可能这一步都是省略的,就是甲方写在一张纸上的几个核心诉求点,然后唯一的后端开发或者全栈小朋友就开始直接翻译,形成一个几页纸的技术方案,其中很大一部分都是ER图,根据ER图直接生成数据库表,有时候可能ER图都是省略的,面向数据库编程的研发模式,然后开始了初期的一顿操作与忙碌,Dao,Service,生怕过一两天就忘了几个表之间的关系,业务逻辑完全寄托在自己的表设计的灵魂上。

如果一个需求就到这里停止了,就是为了设计一个小工具用用,可能面向的群体也是相对固定,自己的小圈子里,加上线下的控制能力,强关联自己的线下组织,那么其实没有多大问题。毕竟软件只是他们的辅助,领域专家就是甲方自己,掌控着核心力量,自己进行日常工作。这也可以说是perfect!

3.产生的痛点

问题:上述的研发过程,关注的是数据存储,所有的业务离不开数据,离不开CURD,数据模型的设计主要是考虑非功能需求,可能着一些考虑也省略了。

所以数据模型的语义表征能力止步于数据库设计人员和能够得到数据库手册的人。

一旦需求发生变化,数据模型就需要变化,对应的数据库设计就要大动,曾经为了数据库设计方便调整,直接使用非关系型数据库,也是此等考虑。

后果:这个研发设计的思路就从需求直接刺穿到数据层,中间没有任何抽象隔离,没有任何稳定的部分,这时候响应变化的能力非常之差。超过两年,这就变成一个无法运维的代码,只能说,能跑就行。

4.解决的思路与北极星目标

解锁新的角色:领域专家

这样做就可以有效的降低产品和研发的认知差异。代码的细节全部隐藏,产品定义的概念全部体现在代码里面,层次结构和代码结构全部和产品的TAPD,外观和逻辑是一摸一样,可以直接基于代码生成一个完整的需求文档,没有概念和命名的区别。

北极星目标:任何系统的设计与概念理论的形成都是基于一个假设。所以在实践过程中,只需要追求实在的东西:可理解性,可维护性,以及代码的可读性。

只做概念上的抽象,不做纯技术上的炫技,不过在Entity内部可以进行技术炫技。这些东西应该无法被轻易找到,而且是可以被轻易替代的。

5.领域对象的生命周期

在编程语言中,每个对象或者变量都是有自己的生命周期。

对象从被创建开始,就会经历各种状态,最后消亡。(要么删除,要么存档)


开始---->活动状态----->结束

图例如下,电脑手绘:

领域驱动设计(1)--概念与生命周期

目前主要是有两个风险:

1.在整个生命周期维护完整性

2.防止模型参与管理的复杂度自带的问题

这里面就引入了两个概念 Aggregate,Factory

前者解决第一个问题,后者和另一个Repository解决第二个问题。

6.讨论Aggregate

情景:如果我们要从数据库删除掉某个具体的Person对象,一般而言,他的姓名,基本信息,工作信息都要一起删除,但是和他有过关系的各种地址如何处理,这就涉及到和别的Person对象共用地址的问题

提炼:我们如何知道一个由其他对象组成的对象从哪里开始,在哪里结束。

进一步提炼:在任何具有持久化的方案里,进行数据修改的事务都要有边界,范围,而且要保证数据的一致性的实现方式。

辨析:这个感觉是编程语言或者数据库的事务问题,在面向数据库软件设计,确实如此,只能是数据库的技术难题。其实,根源是在模型。

模型缺少明确定义的边界。

引入Aggregate:首先需要一个抽象来封装模型的引用。Aggregate 就是一组相关对象的集合。也可以称之为数据修改的单元。每个Aggregate都有一个root根和一个boundary边界。

边界定义了这个集合里面有什么

根是Aggregate包含的一个特殊的Entity.

对于Aggregate而言,外部对象只可以引用根,而边界内部的对象之间则是可以相互引用。除了根以外,其他Entity都有内部私有标识,可以和其他的Aggregate对象保持一致。外部对象是看不到的,只能看到根Entity.

举个例子:

汽车装配厂的软件可能用到汽车模型,汽车就是Aggregate中的根Entity。为了标识这个汽车,可以使用车辆识别号来作为根Entity的标识码。内部其他的Entity可以有轮胎,发动机啥的。脱离了汽车这个Aggregate的上下文,内部的轮胎和发动机,就不需要关心了,更换轮胎或者发动机,就直接废旧回收,也不需要跟踪管理。一般只会有一个逻辑,找到汽车,看看他的零部件,一般不会查零部件在哪个车子上面。同理,发动机一般都有标识码,也可以作为根Entity


总结Aggregate的固定规则:

  • 根Entity具有同一类对象的全局标识,最终负责检查固定规则
  • 边界内的其他Entity具有内部私有标识,内部唯一,同类保持一致,便于统一理解
  • Aggregate外部对象只需要引用根Entity,其他Entity不可见
  • 根Entity可以将内部Entity的引用传递出去,进行使用,传递一个副本,不关心这个副本发生了什么变化
  • 只有根Entity才能被公开在数据库或者文件中直接查询。其他Entity必须是根据根Entity进行遍历关联查询到。
  • Aggregate内部的Entity可以持有别的Aggregate根Entity的引用
  • 删除操作必须是一次删除Aggregate边界之内的所有对象。因为只有根Entity有引用,一旦根删除,其余全都变成孤儿。没有任何引用,被垃圾回收
  • 当修改被提交,不管是内部哪个Entity,整个Aggregate所有上述规定都必须全部被满足。(根控制访问,内部的Entity都不可以绕过它进行修改内部对象Entity.)

这个Aggregate其实就是一个编程规范,既可以通过技术框架进行强制要求,也可以通过文档和审计进行强制约束。当然这本身就是一笔成本开支。

总结:理论只有在工作上遇到切实一致大的困扰,才会被发现价值。它本身就只针对一种情景来设计的。