1.领域驱动发展历史
• 2003年 Eric Evans 《领域驱动设计》 设计的思潮
• 2015年 微服务盛行 服务内聚 焕发第二春
• 2019年 互联网深入实体经济,业务领域变得更加复杂
2.为什么要做领域驱动设计
整体【DDD的作用是简化,而不是复杂化】
随着发展业务会变得越来越复杂:认知成本与协作成本会上升
DDD能减少这两方面的成本
- DDD划分上下文分析领域对象建立业务模型,降低认知成本
- DDD建立通用的模型语言使得团队各个角色都能高效准确的进行沟通,降低协作成本【最大的鸿沟之一便存在于领域专家和开发者之间】
中台战略与DDD
中台本质是业务模型,微服务是业务模型的系统落地,DDD 是一种设计思想,它可以同时指导中台业务建模和微服务设计,它们之间就是这样的一个铁三角关系。
中台是战略目标,DDD是设计思想,微服务是落地手段,云原生是落地基础….企业数字化转型四大核心知识体系,一个都不能少
3.DDD概览
实行DDD的最佳条件(我们满足吗?)
- 业务复杂【才有价值】
- 团队中要有人懂DDD【学习曲线较陡,乱用一通DDD不会带来任何益处】
- 部署容器化(大量的领域服务管理方便)
该如何开始DDD?怎么学?
阅读资料然后马上实践
DDD大体分为哪几部分?
1.战略设计
战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。
产出:
会产生很多的实体、命令、事件等领域对象,我们将这些领域对象从不同的维度进行聚类,形成如聚合、限界上下文等边界,建立领域模型
2.战术设计
战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
产出:
微服务领域对象 和 微服务代码结构
4.DDD建模过程涉及核心概念
这是初次分享,主要是分享概念和思想 , 特别具体的建模过程留到下次或者看参考文档
从战略设计到战术设计简要的说一遍,穿插介绍核心概念
什么是通用语言(Ubiquitous Language)?
团队在限界上下文中发展了一种语言用于表达其边界内的软件模型,这一语言由在该限界上下文中开发软件模型的每个团队成员所使用。它之所以被称之为通用语言(Ubiquitous Language)
例如: 我们团队内说 CR 就代表 代码审查(codeReview),在管理服务费中约定了账单日的概念为“生成管理服务费账单的时间,固定为每月1日”
什么是领域和子域?它都有哪些类型?
领域就是用来确定范围的,范围即边界,这也是 DDD 在设计中不断强调边界的原因。
DDD 会按照一定的规则将业务领域进行细分,当领域细分到一定的程度后,DDD 会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。简言之,DDD 的领域就是这个边界内要解决的业务问题域。
领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。
子域类型:核心域、支撑域、通用子域
核心域:它是一个唯一的、定义明确的领域模型,要对它进行战略投资,并在一个明确的限界上下文中投入大量资源去精心打磨通用语言
支撑域:它是一个唯一的、定义明确的领域模型,要对它进行战略投资,并在一个明确的限界上下文中投入大量资源去精心打磨通用语言
通用子域:通用子域的解决方案可以采购现成的,也可以采用外包的方式,抑或是由内部团队实现,但我们不用为其分配与核心域同样优质的研发资源,甚至都不如支撑子域。请注意不要把通用子域误认为是核心域。我们并不希望对其投资过甚
一般来讲,我们主要将核心域确定, 对于支撑域和通用域可以不进行明确的划分
核心域是我们要大力投入的地方,应该根据公司的业务现状来划分的,公司的核心业务就是核心域
什么是限界上下文(BoundedContext)?
DDD主要关注的是如何在明确的限界上下文中创建通用语言的模型。
限界上下文是语义和语境上的边界。这意味着边界内的每个代表软件模型的组件都有着特定的含义并处理特定的事务。限界上下文中的这些组件有特定的上下文语境和语义理据
例如:我和我表哥他二舅都在一家公司上班, 在公司我们的关系是同事, 在家族里的关系是亲戚
限界上下文的关系有哪些?如何集成?【识别关系】
限界上下文之间的关系
限界上下文和微服务的关系
理论上限界上下文就是微服务的边界。我们将限界上下文内的领域模型映射到微服务,就完成了从问题域到软件的解决方案。
限界上下文是微服务设计和拆分的主要依据。在领域模型中,如果不考虑技术异构、团队沟通等其它外部因素,一个限界上下文理论上就可以设计为一个微服务
实体和值对象
实体是什么?
拥有唯一标识符,且标识符在历经各种状态变更后仍能保持一致。对这些对象而言,重要的不是其属性,而是其延续性和标识,对象的延续性和标识会跨越甚至超出软件的生命周期。我们把这样的对象称为实体
业务上:领域模型中的实体是多个属性、操作或行为的载体,我们可以根据命令、操作或者事件,找出产生这些行为的业务实体对象
代码中:实体类
运行时:实体以 DO(领域对象)的形式存在,每个实体对象都有唯一的 ID。我们可以对一个实体对象进行多次修改,修改后的数据和原来的数据可能会大不相同。但是,由于它们拥有相同的 ID,它们依然是同一个实体
数据库中(持久化后):实体与持久化对象则可能是一对多或者多对一的关系。比如,用户 user 与角色 role 两个持久化对象可生成权限实体,一个实体对应两个持久化对象,这是一对多的场景。再比如,有些场景为了避免数据库的联表查询,提升系统性能,会将客户信息 customer 和账户信息 account 两类数据保存到同一张数据库表中,客户和账户两个实体可根据需要从一个持久化对象中生成,这就是多对一的场景
值对象是什么?
通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体
值对象描述了领域中的一件东西,这个东西是不可变的,它将不同的相关属性组合成了一个概念整体
业务上:值对象只是若干个属性的集合,只有数据初始化操作和有限的不涉及修改数据的行为,基本不包含业务逻辑。值对象的属性集虽然在物理上独立出来了,但在逻辑上它仍然是实体属性的一部分,用于描述实体的特征。
代码中:
- 如果值对象是单一属性,则直接定义为实体类的属性
- 如果值对象是属性集合,则把它设计为 Class 类,Class 将具有整体概念的多个属性归集到属性集合,这样的值对象没有 ID,会被实体整体引用
运行时:
- 属性嵌入的方式
- 序列化大对象
实体和值对象的关系
值对象属于某一个实体
实体包含业务属性、业务行为、业务逻辑。 值对象仅是业务属性的集合,可以有业务方法,但是方法是无副作用的
实体一般对应业务对象,它具有业务属性和业务行为;而值对象主要是属性集合,对实体的状态和特征进行描述
聚合和聚合根
聚合由什么组成?
聚合就是由业务和逻辑紧密关联的实体和值对象组合而成的,聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储,实现数据的持久化
聚合根 + 一系列实体属性
聚合根的主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合、实体之间数据不一致性的问题
如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。
聚合有什么用?
领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,它用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。
聚合在 DDD 分层架构里属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑。聚合内实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。
领域驱动设计的收益(总结)
领域驱动设计不是银弹,并不能是万能的
团队用了领域驱动设计后 不能有明确的一个指标提高了多少多少效率
但是领域驱动设计可以更好的帮助我们进行复杂业务梳理, 这一点从开发上有很直观的感受
附录:领域驱动建模具体的操作方式(可落地)
事件风暴、SWOT分析法
四色建模:https://www.infoq.cn/article/xh-four-color-modeling/
限界纸笔建模:https://insights.thoughtworks.cn/paper-pen-modeling/
COLA 4.0:应用架构的最佳实践https://blog.csdn.net/significantfrank/article/details/110934799