
▼
异步社区2021年度畅销新书奖得主——《解构领域驱动设计》作者张逸,是领域驱动设计专家、系统架构师、高质量编码实践者、微服务系统架构师、大数据平台架构师、敏捷转型咨询师,同时也是K+全球软件研发行业创新峰会联席主席。

-
全局分析阶段
-
架构映射阶段 -
领域建模阶段

— 1 —
全局分析阶段
Who:利益相关者
Why:系统愿景
Where:系统范围
When:业务流程
What:业务场景和业务服务
1
2
要注意区分线上流程和线下流程
不要受到当前业务流程的影响,要考虑流程的优化
注意识别可自动化的环节
要使用上帝视角
业务服务名称:以动词短语形式
描述:作为(角色)我想要(服务功能)以便于(服务价值)
触发事件:可用于判断是业务服务,还是执行步骤
基本流程(成功场景):流程的第一步一定是BC收到了服务请求后执行的第一步
替代流程(失败场景)
验收标准:包含了领域规则
— 2 —
架构映射阶段
1
系统上下文用于确定解空间的边界,而在架构层面,它代表了整个目标系统,可以运用系统分层架构来表现。系统分层架构分为(自下而上):
基础层:对应通用或支撑限界上下文
业务价值层:对应核心限界上下文
边缘层(可选):包括API网关、UI适配和服务聚合
客户端层
2
限界上下文六要素:领域知识、领域对象、知识语境、角色、活动和业务能力
限界上下文两本质:领域模型的知识语境和业务能力的纵向切分
限界上下文四特征:最小完备、自我履行、稳定空间和独立进化
内外分离:内部为领域层,外部为网关层
南北对称:分为南向网关和北向网关
业务维度对限界上下文的识别顺序如下:
根据业务相关性(语义相关性、功能相关性)对业务服务进行归类
对归类的业务服务提炼其共同特征,归纳为业务主体
调整业务主体的边界,包括根据亲密度调整业务服务,根据限界上下文的本质调整业务服务
根据验证原则进一步验证限界上下文,验证原则包括:单一抽象层次原则、奥卡姆剃刀原则、正交原则和最小惊讶原则。
团队维度要求我们为限界上下文建立领域特性团队。领域特性团队的组建基于康威定律、2PTs团队与特性团队的要求。
至于技术维度,则需要根据质量属性如高并发、性能、安全等因素,要求资源隔离,从而独立定义限界上下文。
3
我将上下文映射的模式归为两类:通信协作模式和团队协作模式。
防腐层:菱形对称架构的南向网关
开放主机服务:菱形对称架构的北向网关
发布语言:菱形对称架构的消息契约
共享内核:去掉菱形对称架构的网关层
合作伙伴:反模式
遵奉者:反模式
分离关系
客户方-供应方
发布者订阅者
4
以领域为核心驱动力
以业务能力为核心关注点
系统上下文层次:系统分层架构
限界上下文层次:菱形对称架构
— 3 —
领域建模阶段
1
领域分析建模的参与人包括领域专家和开发团队,应考虑由领域专家作为整个分析建模过程的主导。建模的输入为业务服务规约,输出为领域分析模型。
我采用快速建模法获得领域分析模型。它分为五个步骤:
名词建模:识别业务服务规约中表达领域概念的名词。
动词建模:识别业务服务规约中基本流程中的动词。需要确定领域行为,判断该领域行为是否产生过程数据(凭证),将该过程数据表达的领域概念放入领域分析模型。这一个概念实际上就是四色建模中的时标型对象,即确定什么事(what)、什么时间发生(when),并判断有没有留存的价值(why)。
归纳抽象:遵循统一语言原则,对相似的领域概念给出清晰定义,确定是否相同含义;或者是否可以进一步归纳。
确定关系:确定领域概念之间的关系,重点关注多对多与一对多,关系也可能是一个领域概念。
分配限界上下文:根据领域知识的相关性,并明确知识语境的边界,将领域分析模型的各个领域概念分配到各个限界上下文。
2
领域分析建模的输入为领域分析模型与业务服务规约的基本流程,输出则包含静态的领域设计模型(由聚合组成的类图)和动态的领域设计模型(序列图脚本或序列图)。
与领域设计模型有关的模式包括了实体、值对象、聚合、领域服务、领域事件、资源库和工厂。
实体体现了领域概念,具有ID,值对象体现了领域概念,只关注值。
聚合是边界,边界内为实体与值对象组成的对象树,根为实体,它用于维护领域概念的完整性。聚合之间只能通过聚合根实体建立关系,根实体是聚合唯一的入口和出口。
聚合作为领域建模阶段基本的设计单元,同样具有自治的特征:
不变量:对聚合内各个领域概念之间关系的一种约束
完整性:约束概念关系的一种特殊不变量
一致性:约束数据关系的一种特殊不变量
独立性:如果某个实体具有独立管理生命周期的需求,则独立为单独的聚合
领域服务主要负责:
管理多个聚合之间的协作
管理聚合与端口之间的协作
封装无状态的领域行为
分离独立变化的领域行为
领域事件封装了状态的变化。
工厂负责聚合从无到有的创建,资源库负责聚合生命周期的管理,包括添加、加载、变更、移除。
在获得在限界上下文限定下的领域分析模型后,需要确定各个领域模型对象的聚合边界。过程为:
梳理对象图:梳理领域分析模型,分辨实体和值对象。分辨实体和值对象的依据包括了相等性、不变性、独立性和优先级。
分解关系薄弱处:根据实体关系耦合强度划分聚合。
调整聚合边界:根据聚合的自治特性调整聚合边界。
服务驱动设计分为两个步骤:分解任务和分配职责。它的基础则是角色构造型,结合菱形对称架构,一个限界上下文的角色构造型包括:远程服务、本地服务(应用服务)、领域服务、聚合和端口。
分解的任务会形成一棵任务树,业务服务为任务树的根,组合任务为枝,原子任务为叶。过程为:
流程转任务:将业务服务规约中的基本流程转换为任务
向上归纳:将不可分割的相邻任务归纳为更高的组合任务
向下分解:判断目前未分解的任务是否是原子任务,如果不是,则继续分解;如果当前任务需要的领域知识是一个聚合拥有的,识别为原子任务,如果当前任务访问了外部资源,识别为原子任务。
分配职责是一个固定的流程,将各个任务分配给角色构造型:
业务服务分配给远程服务与应用服务
组合任务分配给领域服务
如果没有访问外部资源,原子任务分配给聚合,否则分配给端口
服务驱动设计最终输出的是动态的序列图脚本,驱动出了领域模型对象的方法,明确了领域对象之间的协作方式。
3
领域实现建模的输入是领域设计模型,以及业务服务规约的验收标准;输出为领域实现模型,包括了领域层的产品代码和测试代码。
领域实现建模推荐采用测试驱动开发。对于限界上下文而言,菱形对称架构与测试金字塔存在一定的对应关系。聚合不依赖任何外部资源,非常易于编写单元测试。领域服务的单元测试可以通过模拟端口来编写。应用服务编写集成测试。远程服务编写契约测试。
服务驱动设计与测试驱动开发可以很好的结合起来。服务驱动设计的方向是由外向内,测试驱动开发的方向是由内向外,服务驱动设计输出的序列图脚本可以作为测试驱动开发的输入。
测试驱动开发遵循Kent Beck提出的简单设计原则:
通过所有的测试:可测试性
尽可能消除重复:可重用性
尽可能清晰表达:可读性
更少代码元素:简单性
测试驱动开发还要遵循Robert Martin提出的三定律:
在编写不能通过的单元测试前,不可编写生产代码
只可编写刚好无法通过的单元测试,不能编译也算不通过
只可编写刚好足以通过当前失败测试的生产代码
测试驱动开发对于领域驱动设计虽非必要,但它有助于提升领域实现模型的质量。
END


