书名:《解构领域驱动设计》
作者:张逸
复杂系统:由大量互相作用的部分组成的系统。这些组成部分相对简单,没有中央控制,组成部分之间也没有全局性的通信,并且组成部分的相互作用导致了复杂行为。
影响阻碍理解能力的要素:
影响阻碍预测能力的要素:
软件系统的构建实则是对问题空间的求解,以获得构成解空间的设计方案。
子领域、限界上下文、分层架构和聚合皆为领域驱动设计的核心元模型,分属战略设计和战术设计,贯穿了从问题空间到解空间的全过程。
领域驱动设计(DDD)需要应对软件复杂度的挑战:
领域驱动设计的开放性是其生命长青的基石,但是它过于灵活的特点也带来了诸多不足。
领域驱动设计统一过程,正是要在开放的方法体系指导之下,提供一种简单有效的最佳实践。
领域驱动设计统一过程是对领域驱动设计进行解构的核心内容!
整个统一过程分为3个连续的阶段:
价值需求和业务需求,它们共同组成了目标系统的问题空间。
价值需求需要从系统价值的角度进行分析获得。5W 模型中前3个共同组成了价值需求。
业务需求由动态的业务流程与静态的业务场景、业务服务构成。
业务服务是全局分析阶段获得的基本业务单元。
形成统一的领域术语,尤其是基于模型的语言概念,是让沟通达成一致的前提。
商业模式画布由9个板块儿构成:
业务流程图(TFD)善于表现业务流程,它通过使用诸如任务流程图、泳道图等图形形象地描述真实世界中各种业务流程的执行步骤与处理过程。
服务蓝图是用于服务设计的主要工具,它以更加全面的视角展现了各种角色之间的协作关系。从上到下有3条分界线:
用例是对一系列活动的描述,通过用例图对主体行为进行可视化建模。
事件风暴是以一种工作坊形式对复杂业务领域进行探索的高效协作方法。
学习循环:开始于对意图和任务焦点的想象,接着是探索与投入,然后是思考和发现模式,最后是决定行动与应用。
该方法将个人的学习过程转变为群体共同工作的学习过程。
利益相关者分为支持者和受益者。
在价值需求分析阶段,支持者更加重要,他们决定目标系统的愿景与范围,确定开发目标系统的约束条件;在业务需求分析阶段,受益者更加重要,他们决定了目标系统的业务流程与业务场景,前提是这些业务需求必须获得支持者的认可。
系统愿景是对目标系统价值需求的精炼提取,若能以精简的话语清晰描述出来,就能帮助团队就项目需要达成的目标达成共识。
系统范围保证了问题空间的开放性,同时又能确保问题空间内业务需求的收敛性。
系统内部以及系统之间通过一系列的协作来为用户提供业务价值,这一协作的过程可以成为业务流程。
业务流程有2个关键点:完整和边界。
业务流程分为:主业务流,变体业务流,支撑业务流。
场景就是角色之间为了实现共同的业务目标进行互动的时空背景。业务场景就是体现业务目标的场景。
业务场景 5W 模型:角色、时间、空间、活动、业务目标。
业务服务是角色主动向目标系统发起服务请求完成的一次完整的功能交互,体现了服务价值的业务行为。
问题空间太大,业务服务又太小,而子领域就是一个不大不小、粒度合理的业务单元。
同构系统:两个复杂结构可以相互映射,并且它们的组成部分可以形成一一对应的映射关系。
整个架构映射阶段由以下3组同构系统构成:
系统上下文对应解空间的范围,它站在组织层面思考利益相关者、目标系统和伴生系统之间的关系。
系统上下文图展现的是利益相关者、目标系统和伴生系统的关系的静态视图。
业务时序图则展现了目标系统与伴生系统之间的动态协作关系。
限界上下文其实是动态的业务流程被边界静态切分的产物。
限界上下文是领域驱动设计战略层面最重要、最基本的架构设计单元。
故限界上下文应该是自治的架构单元:
识别限界上下文的过程,就是将问题空间的业务需求映射到解空间限界上下文的过程。
V型映射过程:
具体分为以下阶段:
对限界上下文的边界的合理性的验证方法:
每个团队会负责一到多个完整的界限上下文,多个界限上下文之间应该是允许并行开发的。
上下文映射建立了限界上下文之间的关系。
上下文映射的目的是让软件模型、团队组织和通信集成之间的协作关系能够清晰呈现,为整个系统的各个团队提供一个清晰的视图。
与通信集成有关的上下文映射模式有:
计算机科学中的大多数问题都可以通过增加一层间接性来解决。防腐层的引入正是“间接”设计思想的一种体现。
防腐层从未提供真正的业务实现,而仅仅是扮演了“隔离”的作用;业务实现被放到了另一个限界上下文中,防腐层会向它发起调用。
当多个限界上下文都需要防腐层时,为了避免代码重复,可以将防腐层升级为一个独立的限界上下文。
开放主机服务,就是定义公开服务的协议,包括通信的方式、传递消息的格式(协议)。
发布语言是一种公共语言,用于两个限界上下文之间的模型转换。
我们将一个限界上下文标记为共享内核时,就意味着它实际上暴露了自己的领域模型,并削弱了限界上下文边界的控制力。
共享内核的成本是耦合导致的面临变化的风险,但是收益确是使用非常便利。我们应该只将那些稳定且具有复用价值的领域模型对象封装到共享内核上下文中。
消息契约对应上下文映射的发布语言模式,根据客户端发起对服务操作的类型,分为命令(动作)、查询(请求)和事件(通知)。
服务契约对应上下文映射的开放主机服务模式,通常指采用分布式通信的远程服务。
不包含领域逻辑的业务服务应被定义为应用服务。
服务时序图的本质是 UML 的时序图,通过消息流产生一种不断向前的设计驱动力。
通过服务契约表列出每个服务契约的定义和设计信息。一般包括服务功能、服务功能描述、服务方法、生产者、消费者、模式、业务服务、服务操作类型等属性。
六边形架构:
开放主机服务模式的设计目标与菱形对称架构的北向网关完全一致。
如果将防腐层防止腐化的目标从上游限界上下文扩大至当前限界上下文的所有外部环境(包括数据库等环境资源和伴生系统),则防腐层就承担了菱形对称架构的南向网关的角色。
保证限界上下文自治的一个关键在于隔离领域模型。除了共享内核模式和尊奉者模式之外,限界上下文不应暴露领域模型,因此需要为北向网关的服务、南向网关的客户端建立消息契约模型。
菱形对称结构:
系统上下文界定了目标系统解空间的范围,对系统上下文进行分层架构来确定整个系统的结构:
领域驱动设计在架构层面获得的抽象元素就是:系统上下文和限界上下文,他们围绕领域为核心驱动力,以业务能力为核心关注点,分别形成了两个层次的架构模式:系统分层架构模式与菱形对称架构模式。
领域模型是以“领域”为关注核心的模型,是对领域知识严格的组织且有选择的抽象。具体分为领域分析模型(概念模型)、领域设计模型(设计)、领域实现模型(代码)。
分析、设计和实现是领域模型驱动设计的3个建模活动。在这个过程中,我们通过统一语言维护领域模型的一致性。
在分析之初,不考虑任何技术实现手段,一切围绕着领域知识进行建模,是领域模型驱动设计的关键。
快速建模法,分为4个步骤:
领域驱动设计鼓励在领域分析建模阶段形成细粒度的领域概念。在分不清一个领域概念是应该保留还是被合并时,应优先考虑保留,待到领域设计建模时再做进一步甄别。
对相同或近似的领域进行建模分析时,可以抽象出相同或相似的模型,形成可以参考和复用的概念模型,即分析模式。分析模式的抽象层次要高于分析模型。
分析模式是由领域专家寻找和总结的,是企业的一份重要资产,可以用于改进领域分析模型。
实际上,在领域分析建模活动中,扮演重要作用的不是开发团队,而是领域专家。
限界上下文是领域模型的的业务边界,即领域模型的知识语境。
战术设计元模型的各种模式与模型元素特点:
值对象通常作为实体的属性,值对象应该是不可变的,也不会被分配任何标识。
使用值对象还是实体?
设计建议:
值对象比内建类型的优势有:
类的关系:
控制类的关系要从以下几点下手:
同时,还需要引入边界来降低和限制领域类之间的关系,防止关系之间的传递无限蔓延。
领域设计模型并非真实世界的直接映射。如果真实世界缺乏清晰的边界,在设计时,我们就应该给它清晰地划定边界。
聚合的定义:
将实体和值对象划分为聚合并围绕着聚合定义边界。选择一个实体作为每个聚合的根,并允许外部对象仅能持有聚合根的引用。作为一个整体来定义聚合的属性和不变量,并将执行职责赋予聚合根或指定的框架机制。
聚合的基本特征:
聚合的设计原则:
聚合的协作办法:
创建时使用工厂方法涉及的设计模式:
创建时使用工厂方法的方式:
资源库是对数据访问的一种业务抽象,可以代表数据库、网络或其他硬件环境。引入资源库,主要目的是管理聚合的生命周期:工厂负责聚合实例的诞生,垃圾回收负责聚合实例的消亡,资源库就负责聚合记录的查询与状态变更。
资源库与数据访问对象(DAO)的在技术层面一致,但区别在于:
领域服务也是一种领域模型。但是它并不代表一个具体的领域概念,而是封装了领域行为。
针对领域行为建模时,优先考虑通过聚合的方式实现,领域服务是领域设计建模的最后选择。
适合使用领域服务的场景:
领域驱动设计将对象的状态提升到更高地位,赋予它领域事件的身份。它是实体、值对象和领域服务的一个重要补充,目的是更好地跟踪实体状态的变更,并在状态发生变更时,通过事件消息的通知完成领域模型对象之间的协作。
领域事件的特征:
各个角色都具有自身的特征,这些特征就是构造型。角色构造型不包括具体行为的描述。
角色构造型分类:(对应关系参考菱形对称架构)
设计聚合的过程:
分解关系薄弱处:
调整聚合边界:
业务服务是全局分析阶段对业务场景进行分解获得的独立的业务行为。
业务服务分为3个层次:最底层的原子任务对应具体的功能实现;其上层的组合任务对应业务功能;最上层的业务任务对应服务价值,即业务服务需要满足的服务请求。
服务驱动设计过程:
领域层的设计目标就是要达到逻辑层的自给自足,一个稳定的领域模型也是最容易执行单元测试的模型。
单元测试保护下的领域核心逻辑,是企业系统的核心资产。确保了正确性、可安全重构、可持续演化。
菱形对称架构和测试金字塔的对应关系:
如果测试编写得体,测试代码也可以认为是一份精炼文档,且这样的文档还具有和实现与时俱进的演进能力,形成一种活文档。
在领域实现建模阶段,保证从设计到实现一脉相承的简单性,最好的方式就是测试驱动开发。
测试驱动开发实际上是要求需求分析优先,任务分解优先。任务分解可以进一步划分为多个可以验证的测试用例,然后按照“测试-开发-重构”的节奏进行编码实现。
测试驱动开发三定律:
功能正确、减少重复、代码可读性是简单设计的根本要求。
一般而言,微服务的粒度要细于或等于限界上下文的粒度:
主要采用的分布式通信机制包括:REST、RPC、消息传递。
CQRS模式是将模型分为命令模型和查询模型。同时,根据命令操作的特性以及质量属性的要求,酌情考虑引入命令总线、事件总线和事件存储。
命令总线是将同步的命令请求改为异步方式,以提高系统的响应能力。一般采用消息队列来实现。
命令端与查询端可以进一步引入事件总线实现两端的完全独立。事件自身携带了事件处理器需要的聚合数据,交由资源库完成对聚合的持久化。
事务是用来确保一致性的技术手段。满足数据强一致性(即ACID)要求的分布式事务称为刚性事务,则满足数据最终一致性的分布式事务称为柔性事务。
业界常用的柔性事务模式包括:
要持久化领域模型对象到关系数据库中,就要为对象与关系建立映射,即ORM。
聚合是最小的设计单元。一个资源库对应一个聚合,故而聚合也是领域模型最小的持久化单元。
资源库的实现取决于开发人员对ORM框架的选择,如Hibernate或MyBatis等。每种框架都有各自的设计思想和原则,也有不同的最佳实践指导。
边界是核心:
纪律是关键:
EAS(企业应用套件)是一款根据软件集团应用信息化的要求开发的企业级一个要办公软件。EAS为企业搭建了一个数据共享与业务协同平台,实现了人力资源、客户资源和项目资源的整合,包括了人力资源管理、客户关系管理、项目过程管理等主要模块。
资源库的实现、应用服务的实现、远程服务的实现。
整体的代码层次结构:
即使采用领域模型驱动设计,不同人针对同一个领域设计的领域模型也会千差万别,其中一个重要原因是:对模型产生根本影响的是建模范式。范式是指一种公认的模型或模式。
面向过程设计,即结构化编程。特点是:数据结构和算法分离,算法用来操作数据结构。
结构建模范式由持久化对象(数据表的映射)和服务对象(实现业务服务)组成。是典型的贫血模型。
领域驱动设计通常采用面向对象的编程范式。核心是职责与抽象。
职责,是从角色拥有何种能力的角度做出的思考。角色则由对象承担。关键点:单一职责原则。
抽象,关键点:依赖注入,封装变化
函数范式的主要特征为:模块化、抽象化和可组合。
若领域驱动设计的整个过程围绕着“事件”进行,就会因此改变我们观察真实世界的方式,这种方式被作者称为事件建模范式。
将整个目标系统视为一个正方体,X维度限定领域驱动设计的内容,Y维度分解领域驱动设计的过程,Z维度涵盖领域驱动设计的实践。
1. 价值需求
(可附上商业模式画布)1.1 利益相关者(终端用户、企业组织、投资人等)1.2 系统愿景(对准企业的战略目标)1.3 系统范围(问题空间的范围和边界)1. 当前状态(已有资源、已有系统、当前业务执行流程)2. 未来状态(希望如何)3. 业务目标(按利益相关者分类)
2. 业务需求2.1 概述(可附上子领域映射图)2.2 业务流程(可附上服务蓝图、泳道图或活动图)2.3 子领域1...n2.3.1 业务场景1...n1. 业务服务1...n(子领域-业务场景-业务服务,3级结构)(1)编号(唯一编号)(2)名称(动词短语描述业务服务名称)(3)描述(作为<角色>,我想要<服务功能>,以便于<服务价值>)(4)触发事件(点击UI控件、伴生系统发送的消息等)(5)基本流程(主流程,执行成功的场景)(6)替代流程(扩展流程,失败的场景)(7)验收标准(以点形式罗列可以接受的条件或业务规则)
1. 系统上下文1.1 概述(系统上下文图)1.2 系统协作1. 业务流程1...n(业务序列图,彼此之间的协作关系)
2. 业务架构2.1 业务组件(限界上下文作为业务组件,业务服务图、服务图)2.2 业务架构视图
3. 应用架构3.1 应用组件(业务组件映射为应用组件)3.2 应用架构视图(系统架构图)
4. 子领域架构4.1 核心子领域1...n4.1.1 概述(上下文映射图)4.1.2 应用组件1...n(组件名、组件描述、组件类型,服务契约定义:服务功能、服务功能描述、服务方法、生产者、消费者、模式、业务服务、服务操作类型)1. 服务契约1...n(服务契约定义,服务质量相关要素:幂等性、安全性、同步/异步,其他设计要素:性能、兼容性、环境等)4.2 支撑子领域(同核心子领域)4.3 通用子领域(同核心子领域)