领域驱动读书笔记

如何使用本书

通用语言作用于某个限界上下文,在一个特定的限界上下文中只使用一套通用语言,并且保证它的清晰性和简洁性

上下文之间的集成关系:

* 开放主机服务
* 发布语言
* 防腐层
* 客户方-供应方
* 合作关系
* 遵奉者
* 共享内核

通过战略和战术设计而成的领域模型应该是架构中立的,当然,在模型周围和模型之间是存在架构的

一种能够支撑限界上下文的架构是六边形架构,它可以辅助其他架构风格,比如面向服务(service-oriented)架构、REST和事件驱动(Event-driven)等

领域模型将产生更多的业务价值,并且更具有持久性

在限界上下文中进行DDD的战术建模。

聚合可以有单个实体组成,也可以有一组实体值对象组成,此时我们必须在聚合的整个生命周期中保证事务上的一致性。聚合拥有事务一致性边界。

聚合实例通过资源库进行持久化,另外,对聚合的查找和获取也通过资源库完成

内部状态所反映的业务规则必须保持完全的一致

领域服务执行特定于领域的操作,其中可能涉及到多个领域对象

领域事件表示领域模型中发生的重要事件。有多种方式可以对领域事件进行建模。在对聚合进行命令操作时,聚合本身将发布领域事件

模块简单来讲,我们可以将模块看成是java中的包或者C#中的命名空间。模块中包含的领域对象应该是内聚在一起的

DDD入门

我能DDD吗?

DDD首先并不是关于技术的,而是关于讨论、聆听、理解、发现和业务价值的,而这些都是为了将知识集中起来。

领域专家并不是一个职位,他可以是精通业务的任何人,他们可能了解更多的关于业领域的背景知识,他们可能是软件产品的设计者,甚至有可能是销售员。

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

为什么我们需要DDD

使领域专家和开发者在一起工作,这样开发出来的软件能够准确地传达业务规则。

在DDD中,每个人都在学习,同时每个人又是知识的贡献者。

战略设计帮助我们理解哪些投入是最重要的;哪些既有软件资产是可以重新拿来使用的;那些人应该被加到团队中?战术设计则帮助我们创建DDD模型中的各个部件。

DDD如何帮助我们

DDD作为一种软件开发方法

DDD关注业务战略。战略设计关注更多的是业务的战略方向,它帮助定义不同团队之间的组织关系,并在这些关系有可能导致项目失败的时候提供早期预警。DDD的战略设计用于清楚地界分不同的系统和业务关注点,这样可以保护每个业务层面的服务。

通过使用战术设计建模工具,DDD满足了软件真正的技术需求。

当你的系统中有30到40个用户故事(use story)或者用例流(use case flow)时,此时软件的复杂性便暴露出来了,你可以考虑采用DDD了。

贫血领域对象描述的是一个缺少内在行为的领域对象。

* 领域对象中主要是些公有的getter和setter方法,并且几乎没有业务逻辑,或者甚至完全没有业务逻辑
* 称为服务层(Service Layer)或者应用层(Application Layer)的代码包含了系统主要的业务逻辑,并且需要领域对象的那些getter和setter方法

你所说的领域对象根本就不是领域对象,而只是将关系数据库中的模型映射到了对象上而已。

JavaBean标准最早是用来辅助Java的可视化设计工具的,旨在将Microsoft的Active X开发方式带到Java平台。Java此举希望开创一个第三方自定义控件市场,就像Visual Basic一样。此后不久,几乎所有的框架和类库都涌入到了JavaBean潮流中,其中包括Java本身的SDK/JDK和第三方类库,比如Hibernate。在.NET平台推出之后,这样的趋势还在继续。

此外,多数的Web框架依然只支持JavaBean规范。如果你想将一个Java对象显示在网页上,该Java对象最好是支持JavaBean规范的。如果你想将HTML表单中的数据传到一个Java对象中,该Java对象也最好是支持JavaBean规范的。

市场上的几乎每种框架都要求对象暴露公有属性。这样一来,多数开发者只能被动地接受那些贫血对象。于是我们便到了“到处都是贫血对象”的地步。

Customer领域对象根本就不是对象,而只是一个数据持有器(data holder)

如何DDD

通用语言是团队共享的语言。领域专家和开发者使用相同的通用语言进行交流。

我们使用通用语言来捕捉特定核心业务领域中的概念和术语,它是一种团队模式。软件模型包含名词、形容词、动词和一些富有含义的语句等,团队成员便通过这些语言进行交流。软件实现和测试中也使用和团队语言一样的通用语言。

通用语言在团队范围内使用,并且只表达一个单一的领域模型

通用语言并不表示全企业、全公司或者全球性的万能的领域语言。

限界上下文和通用语言存在一对一的关系,限界上下文刚好能够容纳下一个独立的业务领域所使用的通用语言。

只有当团队工作在一个独立的限界上下文中,通用语言才是“通用”的。

虽然我们只工作在一个限界上下文中,但是通常我们还需要和其他限界上下文打交道,这时可以通过上下文映射图对这些限界上下文进行集成。每个限界上下文都有自己的通用语言,而有时语言间的术语可能有重叠的地方。

如果你试图将某个通用语言运用在整个企业范围之内,或者更大的、跨企业的范围内,你将失败。

当你开始一个项目,而该项目已经在使用DDD了,此时你需要将你正在开发的独立限界上下文识别出来,这样便在你的领域模型周围加上了一个显式的边界。此时,你应该在这个限界上下文中使用其专属的通用语言,对于那些不包含在通用语言中的概念,你应该拒绝使用。

使用DDD的业务价值

你获得了一个非常有用的领域模型

你的业务得到了更准确的定义和理解

领域专家可以为软件设计做出贡献

更好的用户体验

更好的企业架构

敏捷、迭代和持续建模

使用战略和战术新工具

实施DDD所面临的挑战

三点最常见的挑战:

第一个例子采用的是以数据为中心的方式,此时客户代码必须知道如何正确地将一个待定项提交到冲刺中,这样的模型是不能称为领域模型的。

这种方式同时也暴露了BackLoItem的数据结构,并且将关注点集中在数据属性上,而不是对象行为。你可能会反驳道:“setSprintId()和setStatus()就是行为啊”。问题在于,这里的“行为”没有真正的业务价值,它并没有表明领域模型中的概念–此处即“将待定项提交到冲刺中”

另外,commitTo()的领域行为还包括:在提交待定项完毕后,以事件形式通知相关客户方。如果不是这个富含行为的BackLogItem,我们得在客户代码中发布领域事件,这显然是一种领域逻辑的泄漏。

如果一个限界上下文被当成核心域来开发,那么从战略上来说,这个限界上下文对业务的成功是极其重要的。

一个领域,对于消费方来说有可能成功通用子域(Generic Subdomain)或者支撑子域,但是却有可能成为你自己的核心域。我们并不站在最终消费方的角度来评价一个领域。如果你正在开发的限界上下文是你主要的业务,那么它便是你的核心域,而不管消费方是如何看待的。

围绕领域专家组织自己的团队。

DDD绝非是充满繁文缛节的笨重开发过程。事实上,DDD能够很好的与敏捷项目框架结合起来,比如scrum。DDD也倾向于“测试先行,逐步改进”的设计思路

领域、子域和限界上下文

从广义上讲,领域(Domain)既是一个组织所做的事情以及其中所包含的一切。商业结构通常会确定一个市场,然后在这个市场中销售产品和服务。每个组织都有它自己的业务范围和做事方式。这个业务范围以及在其中所进行的活动便是领域。当你为某个组织开发软件时,你面对的便是这个组织的领域。这个领域对于你来说应该是明晰的,因为你在这个领域中工作。

在DDD中,一个领域被分为若干子域,领域模型在限界上下文中完成开发。

不幸的是,由于现在多数软件系统并没有采用DDD,这个导致少数的几个子系统承担了太多的业务功能。

限界上下文对标真实的物理系统

子域并不是一定要做到很大,并且包含很多功能。有时,子域可以简单到只包含一套算法,这套算法可能对于业务系统来说非常重要,但是并不包含在核心域之中。在正确实施DDD的情况下,这种简单的子域可以以模块(Module)的形式从核心域中分离出来。

“顾客”这个术语可能有多种含义,在浏览产品目录的时候,“顾客”表示一种意思;而在下单的时候,“顾客”又表示另一种意思。原因在于:当浏览产品目录时,“顾客”被放在了先前购买情况,忠诚度、可买产品、折扣和物流方式这样的上下文中。而在下单时,“顾客”的上下文包括名字、产品寄送地址、订单总价和一些付款术语。

在一个好的限界上下文中,每一个术语应该仅表示一种领域概念。

创建支撑子域的原因在于它们专注于业务的某个方面,否则,如果一个子域被用于整个业务系统,那么这个子域便是通用子域

领域中还同时存在问题空间和解决方案空间。在问题空间中,我们思考的是业务所面临的挑战,而在解决方案空间中,我们思考如何实现软件以解决这些业务挑战。

问题空间是领域的一部分,对问题空间的开发将产生一个新的核心域。对问题空间的评估应该同时考虑已有子域和额外所需子域。因此,问题空间是核心域和其他子域的组合。问题空间中的子域通常随着项目的不同而不同,他们各自关注于当前的业务问题,这使得子域对于问题空间的评估非常有用,子域允许我们快速地浏览领域中的各个方面,这些方面杜宇解决特定的问题是必要的。

解决方案空间包含一个或多个限界上下文,即一组特定的软件模型。这是因为限界上下文即是一个特定的解决方案,它通过软件的方式来实现解决方案。

通常,我们希望将一个子域一对一地对应到限界上下文。这种做法显式地将领域模型分离到不同的业务板块中,并将问题空间和解决方案空间融合在一起。

对于问题空间的评估也是有益于理解解决方案空间的。解决方案空间在很大程度上受到现有系统和技术的影响。

开发核心域的解决方案是一种关键性的业务投入

在设计欠佳的软件里,子域和限界上下文之间很难存在一对一的映射关系。这种劣质软件的大量存在已经成为事实,并且是你所不能改变的事实。你只能盼着在项目中通过合适的手段实施DDD,但最终你都需要和那些“不健康”的领域进行集成。因此,当你在分析某个“不健康”限界上下文中的多个隐式模型时,请好好温习一下本章前面所教你的那些技能。