《实现领域驱动设计》读书笔记摘抄(1)—— DDD入门

Administrator 939 2022-01-09

第1章 DDD入门

本章学习路线图

  • 了解DDD可以为你的项目和团队带来哪些好处
  • 如何确定你的项目是否合适采用DDD
  • 了解DDD的常见替代方案和他们将导致的问题
  • 学习DDD基础
  • 学习如何向你的管理层、领域专家和技术成员推销DDD
  • 了解使用DDD时面临的挑战
  • 看看一个正在学习采用DDD的团队是如何工作的

领域驱动设计(Domain Driven Design,DDD)作为一种软件开发方法,它可以帮助我们设计高质量的软件模型。

何为DDD

DDD是关于讨论、聆听、理解、发现和业务价值的,将相关知识集中起来。我们需要学习更多的业务知识,并为DDD的通用语言(Ubiquitous Language)做出贡献。将领域专家引入团队是大有好处的,聆听并尊重他们的观点,他们了解更多的业务知识。

本书中需要掌握的是领域建模中更高层次的概念。不管是初级/中级/高级开发者、架构师、领域专家还是项目经理,不同角色的人都可以从DDD中获益。

领域模型:领域模型是关于某个特定业务领域的软件模型。通常领域模型通过对象模型来实现,这些对象同时包含了数据和行为,并且表达了准确的业务含义。

为什么我们需要DDD

我们需要采用DDD的原因:

  • 使领域专家和开发者在一起工作,这样开发出来的软件能准确地传达业务规则。
  • **“准确传达业务规则”**的意思是说,此时的软件就像是领域专家作为编码人员开发出来的一样。
  • 可以帮助所有人员自我提高。在DDD中,每个人都在学习,同时每个人又是知识的贡献者。
  • 关键在于知识的集中,确保软件知识并不只是掌握在少数人的手中。
  • 当大家都使用相同的**“语言”**进行交流的时候,每个人都能听懂他们所说。
  • 设计就是代码,代码就是设计。
  • DDD同时提供了战略设计和战术设计两种方式。战略设计帮助我们理解哪些投入是重要的;哪些软件资产可以复用;哪些人员应该加入团队?战术设计则帮助我们创建DDD模型种的各个部件。

具有真正业务价值的软件能够很好的符合业务战略,并且将竞争优势融合到解决方案中,此时软件是强相关于业务的。通常来说,领域专家将关注点放在交付业务价值上,而开发者则将注意力放在技术实现上。以此带来的鸿沟将增加软件成本,不能完全反映出软件专家的思维模型。当多个领域专家产生分歧时,由于专业领域问题无法看清全貌,会导致出现相互矛盾的软件全貌。

DDD如何帮助我们?

DDD作为一种软件方法,它主要关注以下三个方面:

  1. DDD将领域专家和开发人员集中在一起,这样开发出的软件才能反映出领域专家的思维模型。领域专家和开发人员创建出一套适用于领域建模的通用语言,并在团队范围内达成一致。
  2. DDD关注业务战略。DDD的战略设计用于清楚地区分不同的系统和业务关注点,这样可以保护每个业务层面的服务,更进一步引导实现面向服务架构或者业务驱动架构。
  3. 使用DDD战术设计建模工具,即满足软件技术需求,也是的开发人员按照领域专家的思维模型开发软件。

处理领域复杂性

我们首先希望DDD应用在最重要的业务场景下,这样的模型命名为核心域,相对次要的成为支撑子域。不同的业务领域对于复杂的定义不一样的,与其定义什么是复杂,还不如定义什么时重要。需要团队和管理层决定的是:你们开发的软件系统是否值得做出DDD投入。

DDD的作用是简化,而不是复杂化。我们应该使用最简单的方式对复杂领域进行建模,而不是使问题更加复杂。

DDD计分卡,通过表格各个计分项目来判断是否值得DDD投入。表格略,详见书中对应章节。_

通过计分卡中项目,可以得出以下结论:

  • 当我们在复杂性问题上犯错误时,我们很难进行调头
  • 在项目计划早期对简单性和复杂性做出判断,会为后期节约很多时间开销,免除很多麻烦。
  • 当我们做出来重要的架构决策并进行了深入地开发,通常就一样强绑定在该架构下,所以决定时一定要非常慎重。

贫血症和失忆症

关于贫血领域对象的描述章节略。主要说的是对象属性和属性列表带(还有相关的getter/setter函数)来的影响,并不是健康的领域对象,无法真正提现出业务价值。在加上历史原因,会更加使人看不懂代码的作用。这种情况称为“由贫血症导致的失忆症”。

TODO:补充相关章节说明和代码示例,就是个案例。

如何DDD

先看DDD最具威力的特性之一:通用语言。通用语言界限上下文同时构成了DDD的两大支柱,相辅相成。

可以将界限上下文看成是整个应用程序内的一个概念性边界。这个边界之内的每种领域术语、词组或句子——也即通用语言,都有明确的上下文含义。

通用语言

通用语言是团队自己创建的公共语言,团队中同时包含领域专家和软件开发人员。

通用语言更多地是关于业务本身如何思考和运作的,即使领域专家对通用语言有很多的影响,不同领域专家存在分歧或犯错,但最终都是为了创建最适合项目的通用语言。通用语言也会随着时间推移不断演化改变以更适合项目。

对于掌握通用语言的一些实验性方法:

  • 同时绘制物理模型图和概念模型图,并标注名字和行为。
  • 创建一个包含简单定义的术语表,或使用其他类型文档来承载。
  • 找团队中其他人来检查成果并不断修改。

由于团队交流和代码才是对通用语言的持续表达,应该试着抛弃那些模型图、术语表和文档。(注:并不严谨,虽然说代码即文档)

TODO:书中将贫血症章节的示例按照业务领域做了修改,示例能直接反映出业务操作,而不是通过大量的set操作进行更新对象。

是通用,但不是万能

在理解通用语言时,需要牢记以下几点(只列举如下,书中其他观点略):

  • 通用语言在团队范围内使用,并且只表达一个单一的领域模型。
  • 界限上下文和通用语言间存在一对一的关系,上下文内部才是通用的。界限上下文刚好能容纳下一个独立的业务领域所使用的通用语言。
  • 和其他界限上下文之间通过上下文映射图进行集成,此时语言间的术语可能存在重叠的地方。

当项目开始使用DDD,需要将正在开发的独立界限上下文识别出来,这样可以在领域模型周围加上一个显式的边界。此时可以在界限上下文中使用专属的通用语言,其他不在内的概念应该拒绝。

使用DDD的业务价值

软件开发者不应该只热衷于技术,应该将眼界放更宽。不管使用什么技术,目的都是提供业务价值(这样才会有人买单)。如果我们提供的技术方案比其他方案更能体现业务价值,我们的业务能力也将增强。

书中将DDD的业务价值总结为以下几点:

  1. 获得一个非常有用的领域模型
  2. 业务得到更准确的定义和理解
  3. 领域专家可以为软件设计做出贡献
  4. 更好的用户体验
  5. 清晰的模型边界
  6. 更好的企业架构?
  7. 敏捷、迭代式和持续建模
  8. 使用战略和战术新工具

TODO:具体解释详见书中说明,用于向管理层、领域专家和技术人员“推销”DDD。

实施DDD所面临的挑战

书中重点讨论以下三个常见的挑战:

  • 为创建通用语言腾出的时间和精力
  • 持续地将领域专家引入项目
  • 改变开发者对领域的思考

最大的挑战之一就是:需要花费大量的时间和精力来思考业务领域,研究概念和术语,并和领域专家交流,以发现、捕捉和改进通用语言。

如我自己所在项目和5G相关,那就需要深入了解5G的各个模块和业务(用户面/信令面)流程。

如果项目中连一个领域专家都找不到,那么你根本无法对一个领域有多深入的了解。开发者也应该和领域专家深入交流,然后将谈话转化为代码。

多数开发者在采用DDD时都需要转变思考方式,多从业务领域角度思考实现方式。

TODO:书中以“提交项目到冲刺阶段”提供两个示例,用于演示对领域模型的设计哪种会更好。第一个是提供getter/setter方法来修改领域对象的属性;第二个使用代码还原领域对象的行为。

为领域建模正名

本章废话比较多,挑一些重点说明(如果看到后续章节有想法再修改补充):

  • 如果一个界限上下文被当成核心域来开发,那么从战略角度看对业务成功及其重要。
  • 一个领域对于消费方来看会成为通用子域或支撑子域,但可能成为你自己的核心域。如果你正在开发的界限上下文是你主要业务,那它便是你的核心域。

业务领域的类型本身不自动地决定应该选择哪种开发方式。你的团队应该考虑些重要问题再做出决定:

  • 团队是否有领域专家,如何围绕领域专家组织团队。
  • 当前看业务领域比较简单,但它将来会变得复杂吗?当变复杂时,是否有可能重构到富含行为的领域模型中?
  • DDD的战术模式是否可以简化与其他界限上下文的集成,不管是第三方还是定制开发?
  • 使用事务脚本能否减少代码量?
  • 你的项目进度安排是否允许在战术模式上有所投入?
  • 在核心域上的战术投入能否消除(个人认为削减更合适)架构变化带来的影响?
  • 客户能否从中获益?

DDD并不笨重

DDD能够和敏捷项目框架结合起来,也倾向于“测试先行,逐步改进”的设计思路。在你开发一个新的领域对象的时,比如实体或者值对象,可以采用如下步骤进行:

  1. 编写测试代码以模拟客户代码是如何使用该领域对象的。

    注:客户是从生产/消费角度来看,说是调用可能好理解一些,并不是实际上的金主爸爸。

  2. 创建该领域对象使测试能够通过。

  3. 同时对测试和领域对象进行重构,直到测试代码能够正确地模拟客户代码,同时领域对象拥有能够表明业务行为的方法签名。

  4. 实现领域对象的行为,直到测试通过为止,再对实现代码进行重构。

  5. 向你的团队展示代码,包括领域专家,以保证领域对象能够正确地反映通用语言。

与“测试驱动开发”基本思路一致,但我们关注的是客户代码如何使用领域对象,此时测试代码驱动着模型设计。此时需要关注的是领域对象对于领域概念的表达力,而测试代码本身便是通用语言在程序的表达。

虚构的案例,真实的实践

书中以一个虚构的公司和虚构的业务来展示团队在进行开发的不同阶段所面临的种种问题,以及如何解决这些问题走向成功。本章节仅介绍该虚构的公司,它的团队和软件项目。