项目中用到了一些DDD的设计,以前也用到过,准备再学习一下《领域驱动设计模式、原理与实践》这本书,以前就看过不过当时云里雾里的,下面就是学习笔记,观点不一定对,很多概念和书上保持了一致,也加入了个人根据实际项目的理解,这样理解会深一些,有些概念后面会详细介绍,不必过于纠结,了解大概即可。
1.为复杂问题域创建软件的挑战
某些业务场景可能会包含非常复杂的逻辑,比如电商、外卖业务。另外很多逻辑是随着业务发展由简单逐渐变的复杂,系统变的复杂后,很多系统代码可读性和可维护性变的很差, 甚至存在随意构造、杂乱无章、凌乱、任意拼接、毫无头绪的代码丛林,代码有作用但是没有人能说清楚怎么运行的,这样架构模式在书中被称为大泥球模式
。复杂问题域的挑战如下:
-
未使用
通用语言
创建代码。缺乏对
通用语言
和问题域
知识导致写的代码实现了功能,但是却无法揭示业务的目的,久而久之就造成了代码模型和真实反应业务逻辑的分析模型
差距越来越大。 -
缺乏围绕问题模型的设计和重视
项目前期开发基于
业务逻辑
需求快速开发完成,但是缺乏对问题域
模型重视,使得后续扩展变的复困难。 -
大泥球模式扼杀开发
很自然这样的代码难以维护,对个人和公司都不是好消息,到了一定程度只能重构,但是如果缺乏应有的关注和考量依然会再次重蹈覆辙。
-
缺乏对
问题域
的关注不能充分理解业务领域,在非功能的需求之外创建并维护一个可以满足业务用例的软件模型是重要且困难的,编写代码其实是最简单的,这也是为啥说开发几年后要专注一个领域的原因吧。但是很多人却认为恰恰相反,甚至感觉所有业务的都是CURD,一把梭哈,不用区分什么行业,业务提什么需求,我就直接把需求翻译成代码。
2.领域驱动设计模式如何管理复杂性
2.1 战略模式
战略模式帮助提炼业务领域中的问题,并塑造项目架构,以下是战略模式的意义
-
提炼问题域以揭示重要之处
领域专家
和开发团队
使用分析模型
将大的问题域提炼成更易于管理的子域
,DDD强调将精力集中放在核心子域
上,保证代码质量,确保跟上业务节奏,确保核心子域
的代码要和业务产生协同,避免成为大泥球模式
,对于非重要的部分甚至可以寻找开源的解决方案,以便将更多时间精力投入到核心子域
。重点领域重点投入
-
创建模型解决领域问题
非现实世界的模型,是满足业务需求的一个抽象体,但是要包含业务领域的规则和逻辑,模型要与基础架构代码分离,不依赖与底层 技术的实现方式。不复杂或者非核心子域可以采用面向过程或者数据驱动形式的架构,不必完全采用基于
富面向对象
设计。这里会在后面实现领域模型的几种方式时提到,还是要根据业务场景做选择,
充血模型
不一定最适合的。 -
使用通用语言建模合作
领域专家
和开发团队
使用通用语言
交流构建领域模型
, 通用语言是不断发展的,涉及的业务的概念、术语都会被准确的定义,当大家都基于通用语言
的交流,能够快速将分析模型
和代码模型
联系在一起,减少了翻译成本。比如对电商来说通用语言包含,商品、上架、下架、取消订单、订单已取消,这个后面在通用语言相关内容会介绍。
-
将模型与歧义和损坏隔离。
模型存在与
有界上下文中
,有界上下文
起到了防护边界的作用,对模型的修改始终在其所属的有界上下文
中,有界上下文
保护了模型的完整性,通过合理的划分有界上下文
将大泥球模式
代码隔离开来,避免污染核心子域。有界上下文可以暂时理解为微服务系统中的一个子系统,一个微服务可以包含一个或者多个模型,但是同一个模型一般在一个微服务内,这个后续在有界上下文管理关系的地方会介绍。
-
理解上下文之间的关联关系
理解微服务的之间的关联关系,帮助开发人员理解业务的宏观状况,微服务的职责和边界、微服务内的模型能力,不同微服务中模型的差异化(比如order系统中的商品模型和shop系统的中的商品模型存在差异),但是这些在业务上不容易清晰的感知到或者理解。
有界上下文可以暂时理解为微服务系统中的一个子系统,有界上下文和微服务之间的差异化部分在后续会说明,这里不展开。
2.2 战术设计
战术设计帮助创建复杂的有界上下文
的一系列方法,说白了就是如何在代码层面上实现复杂的微服务子系统,这块内容比较多,后续会单独介绍。
2.3 问题空间和解空间
-
问题空间
从业务领域中的问题出发,通过
通用语言
交流获取领域知识,然后利用领域知识拆分子域和构建模型,这个理解一般用于新项目,用于降低领域的复杂度,更聚焦核心领域
.
-
解空间‘
领域专家和开发团队基于已有的业务创建一个模型,并在已有的领域中使用,可以影响架构发展变得更容易管理。
3.领域驱动设计的实践和原则
-
专注核心领域 大型项目不必做到全部完美,这一点很难做到,要能够确定
核心领域
,在核心领域
投入最多的精力,因为这是决定项目成败的关键。 -
协作学习
这里只
领域专家
和开发人员要对业务多交流,构建正确的业务模型,增加开发人员对问题域的深刻理解。 -
通过探索和实验创建模型
对于DDD来说
分析模型
和代码模型
是一体的,因为他们通过通用语言
绑定了,分析模型
的突破会导致代码模型
变化,代码模型
变化也会在分析模型
反映出来,所以模型的设计要多花时间探究和实验。 -
使用通用语言交流沟通
业务人员、开发人员、领域专家都使用统一的术语进行沟通,确保沟通语言没有歧义,降低理解成本,最终利用通用语言的约束落实到代码层面。
-
理解模型的适用性
模型在
有界上下文
中,要基于有界上下文
讨论模型的能力,不同上下文的通用语言
可能会有歧义。 -
让模型持续发展
要持续考虑模型对当前业务的有用程度,确保模型和业务逻辑协调,必要的时候可能会打破原有的模型,不得不变更(比如业务模式发生巨大的变化)
4.领域驱动设计的常见误区
-
战术模式是关键
战术模式因为是代码实施层面,可能给人的感觉更容易操作,所以认为只要战术模式使用了DDD风格就一些OK,其实战略模式解决微服务边界、职责、拆分的问题,如果这个问题没有解决好,即使代码用了DDD风格服务之间交互依然是混乱的,但是如果用战略模式,没有用战术模式,其实已经做到了上下文隔离,微服务各个子项目内部逻辑自己就可控了。
-
DDD是万能的
只有复杂的项目才需要DDD设计,简单的不需要,不能盲目的完全照搬,上面多次提到重点关注
核心子域
问题,包括后面会提到的如何实现领域模型相关的问题时,不一定非要按照充血模型
实现,而是要结合业务场景。 -
DDD在2004年提出了,这么多年都没有流行,说明是错误的,不值得学习和应用。
确实DDD很早之前就产生了,之前一直没被广泛关注不能说明它就是脱离实际的产物,因为很多理论有的是超前的,也正是微服务架构的流行才让DDD被再次广泛关注,它的实施成本确实不低。但是我们依然可以学习它的一些理论思想,结合实际需求在项目中运用,即使不能在项目中运用,我们在面临一些微服务职责边界划分、微服务通信接口约束问题时,依然能够在它的思想里面找到一些决策依据,这一点也是有利的。
分析模型: 可以是示意图或者UML图,真实反映业务场景,可以让非技术人员理解。
问题域:可以理解为开发项目的行业,比如外卖、电商、支付,这些行业领域内专业术语和逻辑流程。
网友评论