
本书分别从战略和战术层面详尽地讨论了如何实现DDD,其中包含了大量的最佳实践、设计准则和对一些问题的折中性讨论。全书共分为14章,在DDD战略部分,本书向我们讲解了领域、限界上下文、上下文映射图和架构等内容,战术部分包括实体、值对象、领域服务、领域事件、聚合和资源库等内容。一个虚构的案例研究贯穿全书,这对于实例讲解DDD实现来说非常有用。
序 在本书中,Vaughn Vernon以一种特有的方式向我们展示了领域驱动设计(Domain- Driven Design,DDD)的各个方面,其中包括对新概念的解释、新的例子和原创 的话题组织方式。我相信,这种新颖的方式可以帮助大家掌握DDD的各种微妙之 处,特别是非常抽象的聚合和限界上下文。不同的人习惯用不同的方式来理解这 些概念,而在缺少多种解释的情况下,想要了解这些微妙的抽象概念是非常困难 的。 本书包含了在过去9年中出现在各种论文和讲稿中的对DDD的深层剖析,而 这些是在之前的书籍中没有的。本书将领域事件与实体和值对象一道看作是模 型的基础部件。另外,书中还讨论了“大泥球”(Big Ball of Mud)架构和如何将 其放置在上下文映射图(Context Map)中。Vaughn还向我们阐述了六边形架构 (Hexagonal Architecture),这种新兴的架构与分层架构相比,能够更好地描述我 们要完成的事情。 我是在将近两年前第一次接触到本书内容的,那时Vaughn已经开始撰写本书 有一段时间了。在第一次DDD峰会上,我们中的几个编写了关于DDD的若干话题, 比如有关DDD的新知识,或者DDD社区所期待的一些针对性建议等。Vaughn负责 写聚合部分,这一写便是一个有关聚合的文章系列,并且写得非常出色,最后,这个 系列成为了本书中的一个章节。 在那次峰会上,与会人员们一致认为:一套更加具有规约性的DDD模式是大 有裨益的。诚实地讲,对于软件开发中的任何问题,答案都是“得看情况”。然而, 这对于那些希望学到实际应用技术的人来说却没多大用处。人们需要更加实际的 指导。经验法则不见得一定要放之四海而皆准,但在通常情况下,他们可以工作得 很好,也应该被首先尝试。出于自身的果决性,这些经验法则蕴含着解决问题的思 想方法。Vaughn的这本《实现领域驱动设计》将各种明晰的建议很好地融合在一 起,同时又给出了一些折中性的讨论,从而避免了将这些建议过于简单化。 xx 序 一些额外的DDD模式,比如领域事件,已经成为了DDD的主流模式,人们也 学会了如何应用这些模式,并尝试着在新架构和新技术中采用这些模式。在我的《 领域驱动设计:软件核心复杂性应对之道》出版9年后,有太多关于DDD的新知识 需要谈及,Vaughn的这本书则是最全面的阐述。 —Eric Evans Domain Language, Inc. 前言 所有的计算都表明它不工作,唯一的做法是:使其工作。 ——Pierre-Georges Latécoère 早期法国航空企业家 是的,我们将使其工作。然而,在软件开发过程中采用领域驱动设计却是困难 的。即便是有能力的开发者,也很难找到实现领域驱动设计的正确方法。 起飞,着陆 在我小的时候,我的父亲学习过驾驶小型飞机。我们经常会全家出去飞行,有 时会飞到另一个机场,在那里吃过午饭后再返回。当父亲时间有限而他依然想飞 时,父亲便带上我一起在机场上空盘旋,起飞,着陆,再起飞,再着陆。 也会有些长途飞行,这时我们会带上一张由父亲先前绘制好的路线图。我们几 个小孩便当起了领航员:将图上的标志对应着陆地上的地标,以确保我们没有跑 偏航线。这是一件很有趣的事情,因为要识别远在地面上的物体是很有挑战性的。 事实上,我敢肯定父亲根本不用我们领航便知道我们处于什么方位——他能看到 仪表盘上的所有信息,并且他拥有仪表飞行执照。 空中的景观的确改变了我的视野。不时地,父亲和我会飞过我们乡下的房子。 在几百英尺的高空中,我体会到了另一种“家”的概念,而这在之前是没有过的。当 我们飞过自家的房子时,母亲和我的姐妹们便会跑到院子里向我们挥手。我知道那 是她们,即便我看不清楚她们是谁。谈话肯定是不行的,连大声喊都不行,她们是 听不见的。我还可以看到将我家和外面公路分开的护栏,平时我们会像走平衡木 一样在护栏上面走来走去。从空中看,它们就像被细心编排过的小树枝一样。我们 xxii 前言 家的院子很大,每每到了夏天,我都会开着割草机一排一排地修理院子里的草坪。 而在空中时,我只能看到一片绿色,小草的叶子肯定是看不清楚的。 我喜欢在空中的时刻,直到现在我还不时回想起这些时刻,好像那个降落飞 机的黄昏就发生在不久以前一样。虽然如此,在地面上的感觉依然是无法取代的, 因为它给我一种脚踏实地的感觉。 着陆于领域驱动设计 一开始接触领域驱动设计(DDD)就像一个小孩之于飞行一样。天空中的景 色是令人惊叹的,但有时我们却因为过于陌生而搞不明白它们到底是什么。要从甲 地到乙地显得如此的遥远。然而,DDD的“成年人”们却总知道他们所处的方位,因 为他们在很早之前便绘制好了路线图,并且能够完全按照仪表进行相应的操作。而 还有很多人找不到“在地面上”的感觉,此时我们需要的是“稳定着陆”的能力,然 后找到一张地图给我们指引方向。 Eric Evans的《领域驱动设计:软件核心复杂性应对之道》是一本经得住时间考验 的经典之作。我坚定地相信,在接下来的几十年里,本书依然会是开发者的实用指 导。和其他模式一样,该书为我们建立起了一种高屋建瓴式的宽阔视野。然而,对 于如何实现DDD,我们可能将面对更多的挑战。通常来说,我们更渴望看到一些具 体的例子。 我的目标之一便是帮助你来一个“软着陆”,保全飞机,然后沿着一条周知的 线路带你回家。这将帮助你如何更好地去实现DDD,并且通过你所熟悉的工具和 技术给出示例演示。当然,任何一个人都不可能一直呆在家里,所以我还会带领你 到新的地带去冒险,这些地带你可能从来没有去过。冒险之路是险峻的,但是在正 确的战术应对下,征服这些困难是可能的。在这条冒险之路上,你将学到另外的架 构和模式来集成多个领域模型。你将接触到先前没有被研究过的集成方法,并且 学到如何开发自治性服务。 我将向你提供一张对短途旅行和长途旅行均适用的地图,它可以帮助你更好 地享受沿途风景,同时又不至于迷失途中。 前言xxiii 对照地形,绘制飞行图 在软件开发的过程中,我们经常做的一件事便是将一种东西映射到另一种东 西。我们将对象映射到数据库,映射到用户界面,或者映射到不同的应用层展现 (包括作为消费方的其他系统或应用程序)。在所有这些映射中,我们很自然地希 望在Evans提出的高层模式和具体实现之间存在一种映射。 即便你已经接触过DDD,你依然有很多可以获益的地方。有时,DDD首先被 看作是一套技术工具集,有人将此称为DDD-Lite。我们可能已经对实体、服务等 DDD概念非常熟悉了,并且大胆地尝试着设计聚合,还通过资源库来管理持久化。 这些模式是大家相对熟知的,使用起来很容易,我们甚至还使用了值对象。以上这 些都属于战术设计模式范畴,也即更加偏向技术层面。这些模式可以很好地帮我 们解决软件问题。而同时,对于战术性模式,我们依然有许多需要学习的。我将战 术模式映射到实现层面。 你曾了解过战术建模之外的东西吗?你曾了解过被称为DDD“另一半”的战略 设计模式吗?如果你还没有使用过限界上下文和上下文映射图,那么你很有可能也 没有使用过通用语言。 如果说Evans在软件开发社区有一项发明,那便是通用语言。通用语言是一种 团队协作模式,用于捕捉特定业务领域中的概念和术语。一个特定领域的软件模 型通过不同的名词、形容词和动词来表达,这些词汇是开发团队正式使用的,而团 队中应该包含一个或多个领域专家。然而,将通用语言仅限定于一些词汇则是错 误的。就像自然语言反映人们的思想一样,DDD的通用语言反映了领域专家对于 软件系统的思维模型。通用语言和那些战略和战术性的建模模式同等重要,在有 些情况下甚至更具有持久性。 简单地讲,DDD-Lite将导致劣质的领域对象,因为通用语言、限界上下文和上 下文映射图的作用太大了,你从其中获得的并不只是一套团队共用的语言。在限界 上下文中用通用语言来表述一个领域模型可以增加业务价值,并且使我们确信所 开发软件的正确性。即使从技术的角度,它也可以帮助我们创建更好的领域模型, 这样的模型行为丰满,业务纯净,并且可以减少犯错误的可能性。因此,我将战略 设计模式映射到了可理解的实际例子中。 本书对于DDD的映射可以帮助你同时体会到战略设计和战术设计的好处。通 过一些具体的例子,你将感受到这些DDD映射的业务价值和技术展现力。 xxiv 前言 如果我们对于DDD的所有实践都只是停留在“地面上”,那将是令人失望的。 过度地拘泥于细节将使我们丧失在空中俯瞰的机会。所以,不要将自己局限在地 面的细节上,要勇敢地飞翔在空中,居高临下。搭上战略设计的航班,去了解限界上 下文和上下文映射图,你将获得更广阔的视野。当你从DDD的航班中获益时,我的 目的也就达到了。 各章概要 以下是各章的主要内容以及你将如何从中获益。 第1章:DDD入门 本章向你介绍DDD的好处,并且教你如何尽可能多地去实现DDD。你将学到 当你在应对复杂的软件系统时,DDD可以为你的项目和团队带来什么。同时,你将 了解到通常的DDD替代方案以及这些方案为什么会导致问题。作为对DDD的基础 讲解,本章将教你如何在项目中开始采用DDD,还有如何向你的领域专家和技术 团队推销DDD。在DDD的武装下,你将学会如何迎接挑战,勇往直前。 本章将介绍关于一个公司及其团队的案例研究,虽然该公司是虚构的,但 是他们所面临的DDD挑战却是真实存在的。该公司旨在开发一个新的多租户 SaaS(Software as a Service,软件即服务)软件产品。不出所料,在使用DDD时,他 们犯了一些常见的错误。不过还好,他们发现了这些错误,并解决了一些问题,因此 项目还算没有偏离正轨。该团队需要开发一套基于Scrum的项目管理软件。该案例 还会在本书的后续章节中连续讲到。每一种战略和战术模式都将教给这个团队。 在这个过程中,团队有误入歧途的时候,但最终他们将向着成功的DDD实践昂首 阔步。 第2章:领域、子域和限界上下文 领域、子域和核心域分别是什么?限界上下文是什么,我们为什么要使用它,并 且如何使用?这些问题将在这个SaaS项目团队犯错误的时候给予解答。在他们的 第一个DDD项目中,他们并不了解子域、限界上下文和通用语言这些概念。事实上, 他们根本不知道什么是战略设计,只是采用了战术设计来解决一些技术问题。这 样他们在开始设计领域模型的时候便遇到了不少问题。幸运的是,他们及时地意 识到了这些问题,项目还有挽回的余地。 前言xxv 本章还讲到了如何使用限界上下文对模型进行分离,这是非常重要的;同时 还讲到了一些模型分离不当的反例,并且给出了有效的实现建议。在采用了这些建 议之后,该团队的成员们重新创建了两个不同的限界上下文。这种合理的模型分离 带来的好处是引出了第三个限界上下文——核心域,这将是本书使用的主要例子。 对于那些苦于单单从技术层面应用DDD的人来说,本章应该能引起你的共 鸣。如果你还是DDD战略设计的外行,那么本章将为你指明方向。 第3章:上下文映射图 上下文映射图帮助我们理解业务领域、模型间的边界,以及这些模型之间的 集成方式。 上下文映射图绝对不只是绘制系统架构图这么简单,它处理的是不同限界上 下文之间的关系,以及如何在不同的模型之间映射对象。对于在复杂的业务系统 中使用好限界上下文,这是至关重要的。在第2章中,团队成员们在首次尝试限界上 下文时碰到了问题。本章中,他们将学着如何利用上下文映射图来解决这些问题。 这样的结果是产生了两个体面的限界上下文,这两个上下文将被另外一个负责核心 域的团队所使用。 第4章:架构 我们都知道分层架构,但它是开发DDD软件的唯一方式吗,也或许还存在 另外的方式?在本章中,我们将讲到:六边形架构(端口和适配器)、面向服务架 构、REST、CQRS、事件驱动(管道和过滤器,长时处理过程,事件源)和数据网 格,其中好几种架构都将被该团队成员所采用。 第5章:实体 在DDD的战术模式中,我们将首先讲到实体。团队成员们一开始过于强调实 体的作用而忽视了值对象。受到数据库和持久化框架的影响,实体被该团队滥用 了,此时他们开始讨论如何避免大范围地使用实体。 在本章中,你将看到很多优秀的实体设计例子。同时,本章还将讲到如何使用 实体来表达通用语言,以及如何对实体进行测试、实现和持久化。 xxvi 前言 第6章:值对象 早些时候,团队成员们错过了采用值对象的好机会。他们过于注重为实体创 建一些单一的属性,这种方式是欠妥的,更好的方式是将这些单一的属性聚合成 一个不变的整体。本章将从不同的角度讲解如何设计值对象,以及在什么时候采 用值对象会优于实体。同时,本章还包含了一些其他话题,比如值对象在集成中的 角色和对标准类型的建模等。然后,本章讲到了如何设计以领域为中心的测试,如 何实现值对象。此外,本章还讲到了在聚合中存储值对象时,如何避免持久化机制 所带来的不利影响。 第7章:领域服务 本章将讲到,在领域模型中,什么时候应该将一个概念建模成粒度适中,并且 无状态的领域服务。你将学到何时应该使用领域服务而不是实体或值对象,以及 如何使用领域服务来处理业务逻辑和技术上的集成。团队成员们向我们展示了何 时应该使用领域服务,以及如何设计领域服务。 第8章:领域事件 Eric Evans并没有在他的书中正式介绍领域事件,领域事件是在他那本书出版 之后才进入人们视野的。在本章中,你将学到为什么领域事件如此有用,以及使用 领域事件的不同方法。领域事件甚至被用来辅助集成和自治性服务。在软件系统 中,我们经常使用一些技术层面的事件机制,但本章将着重讲解领域事件与这些 事件机制的区别。本章还将指导你如何设计并实现领域事件,包括一些可行的方 案和对这些方案的权衡选择。然后,本章将讲到如何创建一个发布-订阅机制;如 何利用事件来集成整个企业软件中的各个订阅方;如何创建和管理事件存储;如 何处理消息机制所面临的常见挑战等。 第9章:模块 对于模型中的对象,我们应该如何将他们组织在大小适中的容器中呢?我们 又如何保证不同容器中的对象之间只存在有限的耦合?另外,我们如何对这些容 器进行命名以体现通用语言?除了包和命名空间之外,我们如何使用由语言和框架 提供的现代模块化机制,比如OSGi和Jigsaw?在本章中,你将看到SaaS团队成员 是如何在不同的项目中使用模块的。 前言xxvii 第10章:聚合 在DDD的战术模式中,聚合可能是最不容易理解的了。然而,在遵循一定的 经验法则的情况下,我们是能够更简单、更快地实现聚合的。在本章中你将学到: 如何利用聚合在不同的小规模对象集群间创建一致性边界,从而降低模型的复杂 性。由于在细枝末节上花了太多精力,SaaS团队成员们在设计聚合时总是磕磕绊 绊。我们将仔细研究该团队所面临的挑战,并且分析错误的原因以及他们的应对 策略。结果,团队成员们对他们的核心域有了更深层次的理解。我们将看到,在合 理的事务处理和保证最终一致性(Eventual Consistency)的前提下,该团队更正了他们 所犯的错误,并且在一个分布式环境中设计出了更具有伸缩性和更高效的模型。 第11章:工厂 工厂已经在[Gamma et al.]中被大量地谈及了,为什么还要讲呢?本章并不打算 重蹈覆辙,而是将重点放在“工厂应该存在于何处”这个问题上。在本章中,我们 将讲到在DDD中实现工厂的技巧。团队成员在他们的核心域中创建的工厂可以简 化客户端接口,并且对模型的消费方起到保护作用,从而避免了在多租户环境中引 入灾难性的bug。 第12章:资源库 资源库只是一个数据访问对象(Data Access Object, DAO)吗?如果不是,它 们之间有什么区别呢?我们为什么应该将资源库看成是对集合的模拟而非数据库 呢?在本章中,我们将讲到如何利用ORM来实现资源库,其中有两种ORM方案, 一种采用基于网格的分布式缓存,另一种则采用NoSQL的键值对存储。团队成员 们可以采用任何一种作为他们的持久化机制。 第13章:集成限界上下文 到现在为止,你已经了解了战略层次的上下文映射图和多种战术层次的模式。 本章将讲到,在DDD中,我们如何通过上下文映射图来集成不同的模型。在团队对 核心域和其他辅助性的限界上下文进行集成时,我们将给出相应的建议和指导。 xxviii 前言 第14章:应用程序 对于每一个核心域的通用语言,我们都设计了相应的模型,并且进行了足够的 测试,模型工作正常。然而,客户应该如何使用我们的模型呢?他们应该使用DTO 将数据在模型和用户界面之间传输吗?或者存在其他方案可以实现模型和展现组 件间的数据传递?DDD中的应用服务和基础设施是如何工作的?对于这些问题, 本章都将做出解答。 附录A:聚合与事件源:A+ES 事件源是一种持久化聚合的重要技术,同时也是事件驱动架构的基础。事件 源通过一系列的事件来表示聚合的所有状态。通过有序的事件重放,我们可以重 新构建聚合的状态。当然,使用事件源的前提是:它能够简化对数据的持久化,并 且能够捕捉到那些具有复杂行为属性的概念。 Java和开发工具 本书中的绝大多数例子都是使用Java语言编写的。我本来可以用C#的,但是我 有意识地使用了Java。 首先,我认为Java社区正在抛弃好的软件设计和开发实践。现在,对于多数 Java项目而言,要在其中找到一个好的领域对象恐怕是困难的。在我看来,Scrum和 敏捷被人们看成了优良设计的替代品,而其中的产品待定项(Product Backlog)被看 成了设计本身。多数敏捷人士并不会过多地去思考这些待定项是否会影响到业务 模型。我得说明,Scrum的本意绝对不是要取代设计。不管有多少项目经理想将你 捆绑在持续交付这条路上,我得说Scrum并不仅仅是要取悦于那些甘特图(Gantt chart)的追随者们。然而,太多的时候,情况的确是这样的。 我认为这是个很大的问题,所以我想鼓励Java社区重新回到领域建模中来, 同时我会通过本书向大家说明,设计是可以使我们获益的。 此外,在.NET社区中已经有很好的DDD资源了,比如Jimmy Nilsson的《领 域驱动设计与模式实战》[Nilsson]。由于Jimmy的出色工作和其他人对Alt.NET 的倡导,.NET社区中正掀起一阵优秀设计的开发浪潮,这是Java社区需要注意 的。 前言 其次,我意识到C#.NET人员在理解Java代码上并不存在什么困难。由于很多 DDD社区的人都在使用C#.NET,而本书的早期校对人员也都是C#程序员,但是我 从来就没有收到他们的抱怨。因此,我便不用顾虑这些了。 在我写这本书时,业内正将目光从关系型数据库转向基于文档和键值对的存 储方案。这是有原因的,Martin Fowler将这些存储方案称为“面向聚合存储”。这 种命名是恰当的,它很好地描述了在DDD中使用NoSQL的好处。 但是,就我从事咨询的经验来看,很多开发者还是认定了关系型数据库和对 象-关系映射。因此我想,NoSQL追随者们应该能够理解我在书中包含对象-关系 映射的章节。然而,我的确得承认,这可能会招致那些认为存在对象-关系阻抗失配 (Object-Relational Impedance)的人的鄙视。这无所谓,对此我表示接受,因为绝 大多数人在他们的日常工作中都还得面对这种对象-关系阻抗失配。 当然,在第12章“资源库”中,我同样提供了基于文档的、键值对的和数据网 格的存储方案。在多处地方,我都讨论到了NoSQL对聚合设计的影响。NoSQL趋 势很有可能持续下去,那些对象-关系型的开发者们应该注意了。在本书中你将看 到,我能够同时理解两个阵营的观点,并且对于双方的观点我都同意。这些都是技 术趋势所导致的摩擦,而这对于积极的变革是有必要的。
目录 序 ....................................................................................... xix 前言 ................................................................................... xxi 致谢 ................................................................................. xxxi 关于作者 ......................................................................... xxxv 如何使用本书..................................................................xxxvii 第1章 DDD入门 ....................................................................1 我能DDD吗? ....................................................................................2 为什么我们需要DDD .........................................................................5 如何DDD .......................................................................................... 17 使用DDD的业务价值 .......................................................................22 1.你获得了一个非常有用的领域模型 ......................................22 2.你的业务得到了更准确的定义和理解 ..................................23 3.领域专家可以为软件设计做出贡献 ......................................23 4.更好的用户体验 .....................................................................23 5.清晰的模型边界 ....................................................................24 6.更好的企业架构 ....................................................................24 7.敏捷、迭代式和持续建模 ......................................................24 8.使用战略和战术新工具 .........................................................24 实施DDD所面临的挑战...................................................................25 虚构的案例,真实的实践 ................................................................. 33 本章小结 ...........................................................................................36 第2章 领域、子域和限界上下文 ............................................37 总览 ................................................................................................... 37 工作中的子域和限界上下文 ..................................................... 38 将关注点放在核心域上 ........................................................... 42 战略设计为什么重要 ....................................................................... 45 现实世界中领域和子域 ....................................................................48 x 目录 理解限界上下文 ................................................................................ 53 限界上下文不仅仅只包含模型 ................................................. 57 限界上下文的大小 .................................................................... 59 与技术组件保持一致 ............................................................... 61 示例上下文........................................................................................ 62 协作上下文 ................................................................................63 身份与访问上下文 ....................................................................69 敏捷项目管理上下文 ................................................................ 71 本章小结 ...........................................................................................73 第3章 上下文映射图 ............................................................75 上下文映射图为什么重要 ................................................................ 75 绘制上下文映射图 ....................................................................77 产品和组织关系 .......................................................................79 映射3个示例限界上下文 ..........................................................82 本章小结 ...........................................................................................97 第4章 架构 .........................................................................99 采访一个成功的CIO....................................................................... 100 分层 ................................................................................................. 104 依赖倒置原则 ......................................................................... 107 六边形架构(端口与适配器) ........................................................ 110 面向服务架构 ..................................................................................114 REST ................................................................................................117 REST作为一种架构风格 .........................................................117 RESTful HTTP服务器的关键方面 ........................................ 118 RESTful HTTP客户端的关键方面 ........................................ 119 REST和DDD .......................................................................... 120 为什么是REST? ................................................................... 121 命令和查询职责分离——CQRS.................................................... 121 CQRS的各个方面 ................................................................... 123 处理具有最终一致性的查询模型 ......................................... 128 事件驱动架构 ................................................................................. 129 目录xi 管道和过滤器 ......................................................................... 131 长时处理过程(也叫Saga) ................................................... 134 事件源 ..................................................................................... 140 数据网织和基于网格的分布式计算 .............................................. 143 数据复制 ................................................................................. 144 事件驱动网织和领域事件 ..................................................... 145 持续查询 ................................................................................. 145 分布式处理 ............................................................................. 146 本章小结 ......................................................................................... 148 第5章 实体 ........................................................................ 149 为什么使用实体 .............................................................................. 149 唯一标识 ......................................................................................... 151 用户提供唯一标识 ................................................................. 152 应用程序生成唯一标识 ......................................................... 153 持久化机制生成唯一标识 ...................................................... 156 另一个限界上下文提供唯一标识 .......................................... 160 标识生成时间 ......................................................................... 161 委派标识 ................................................................................. 163 标识稳定性 ............................................................................. 165 发现实体及其本质特征 .................................................................. 167 揭开实体及其本质特征的神秘面纱 ...................................... 168 挖掘实体的关键行为 ............................................................. 172 角色和职责 ............................................................................. 176 创建实体 ................................................................................. 181 验证 ......................................................................................... 183 跟踪变化 ................................................................................. 192 本章小结 ......................................................................................... 192 第6章 值对象 .................................................................... 193 值对象的特征 ................................................................................. 194 度量或描述 ............................................................................. 195 不变性 ..................................................................................... 195 xii 目录 概念整体 ................................................................................. 196 可替换性 ................................................................................. 199 值对象相等性 .........................................................................200 无副作用行为 ......................................................................... 201 最小化集成 .....................................................................................204 用值对象表示标准类型 .................................................................206 测试值对象 ..................................................................................... 210 实现 ................................................................................................. 214 持久化值对象 ................................................................................. 219 拒绝由数据建模泄漏带来的不利影响 ..................................220 ORM与单个值对象 ................................................................ 221 多个值对象序列化到单个列中 ..............................................224 使用数据库实体保存多个值对象 ..........................................225 使用联合表保存多个值对象 .................................................229 ORM与枚举状态对象 ............................................................230 本章小结 ......................................................................................... 233 第7章 领域服务 ................................................................235 什么是领域服务(首先,什么不是领域服务) .............................. 237 请确定你是否需要一个领域服务 .................................................. 238 建模领域服务 ................................................................................. 241 独立接口有必要吗 ..................................................................244 一个计算过程 .........................................................................246 转换服务 .................................................................................249 为领域服务创建一个迷你层 .................................................250 测试领域服务 .................................................................................250 本章小结 ......................................................................................... 253 第8章 领域事件 ................................................................255 何时/为什么使用领域事件 ............................................................. 255 建模领域事件 ................................................................................. 258 创建具有聚合特征的领域事件 ............................................. 263 身份标识 .................................................................................264 目录xiii 从领域模型中发布领域事件 .......................................................... 265 发送方 ..................................................................................... 265 订阅方 .....................................................................................269 向远程限界上下文发布领域事件 .................................................. 271 消息设施的一致性 ................................................................. 271 自治服务和系统 ...................................................................... 272 容许时延 ................................................................................. 273 事件存储 ......................................................................................... 274 转发存储事件的架构风格 .............................................................. 279 以REST资源的方式发布事件通知 ........................................ 279 通过消息中间件发布事件通知 .............................................. 283 实现 .................................................................................................284 发布NotificationLog ............................................................... 285 发布基于消息的事件通知 ......................................................290 本章小结 .........................................................................................297 第9章 模块 .......................................................................299 通过模块完成设计 .........................................................................299 模块的基本命名规范 .....................................................................302 领域模型的命名规范 .....................................................................302 敏捷项目管理上下文中的模块 ......................................................305 其他层中的模块 .............................................................................308 先考虑模块,再是限界上下文 ........................................................309 本章小结 ......................................................................................... 310 第10章 聚合 ...................................................................... 311 在Scrum核心领域中使用聚合 ....................................................... 312 第一次尝试:臃肿的聚合 ....................................................... 313 第二次尝试:多个聚合 ........................................................... 314 原则:在一致性边界之内建模真正的不变条件 .............................317 原则:设计小聚合 ........................................................................... 319 不要相信每一个用例 ............................................................. 321 原则:通过唯一标识引用其他聚合 ............................................... 322 xiv 目录 通过标识引用使多个聚合协同工作 ...................................... 324 建模对象导航性 ..................................................................... 325 可伸缩性和分布式 ................................................................. 326 原则:在边界之外使用最终一致性 ............................................... 327 谁的任务? ............................................................................. 328 打破原则的理由 ............................................................................. 329 理由之一:方便用户界面 ........................................................ 329 理由之二:缺乏技术机制 ....................................................... 330 理由之三:全局事务 ............................................................... 331 理由之四:查询性能 ............................................................... 331 遵循原则 ................................................................................. 332 通过发现,深入理解 ...................................................................... 332 重新思考设计 ......................................................................... 332 估算聚合成本 ......................................................................... 334 常见用例场景 ......................................................................... 335 内存消耗 ................................................................................. 336 探索另外的设计 ..................................................................... 337 实现最终一致性 ..................................................................... 338 这是Scrum团队成员的任务吗? ........................................... 339 决定的时候到了 ..................................................................... 341 实现 ................................................................................................. 341 创建具有唯一标识的根实体.................................................. 342 优先使用值对象 ..................................................................... 343 使用迪米特法则和“告诉而非询问”原则 .............................344 乐观并发 .................................................................................346 避免依赖注入 .........................................................................348 本章小结 ......................................................................................... 349 第11章 工厂 ...................................................................... 351 领域模型中的工厂 ......................................................................... 351 聚合根中的工厂方法 ...................................................................... 352 创建CalendarEntry实例 ......................................................... 353 创建Discussion实例 ............................................................... 357 目录xv 领域服务中的工厂 ......................................................................... 358 本章小结 ......................................................................................... 361 第12章 资源库 ..................................................................363 面向集合资源库 .............................................................................364 Hibernate实现 ......................................................................... 369 TopLink实现 ........................................................................... 377 面向持久化资源库 .......................................................................... 379 Coherence实现 ....................................................................... 381 MongoDB实现 ........................................................................ 386 额外的行为 ..................................................................................... 391 管理事务 ......................................................................................... 393 警告 ......................................................................................... 397 类型层级 ......................................................................................... 397 资源库 vs 数据访问对象(DAO) .................................................400 测试资源库 ..................................................................................... 401 以内存实现进行测试 .............................................................404 本章小结 .........................................................................................407 第13章 集成限界上下文 .....................................................409 集成基础知识 .................................................................................409 分布式系统之间存在根本性区别 ...........................................411 跨系统边界交换信息 ..............................................................411 通过REST资源集成限界上下文 .................................................... 417 实现REST资源 ....................................................................... 418 使用防腐层实现REST客户端 ................................................ 421 通过消息集成限界上下文 .............................................................. 428 从Scrum的产品负责人和团队成员处得到持续通知 .................... 428 你能处理这样的职责吗? ..................................................... 434 长时处理过程,以及避免职责 ............................................... 439 长时处理过程的状态机和超时跟踪器 .................................. 450 设计一个更复杂的长时处理过程 ..........................................460 xvi 目录 当消息机制或你的系统不可用时 ...........................................464 本章小结 .........................................................................................465 第14章 应用程序 ...............................................................467 用户界面 .........................................................................................469 渲染领域对象 ......................................................................... 470 渲染数据传输对象 ................................................................. 471 使用调停者发布聚合的内部状态 .......................................... 471 通过领域负载对象渲染聚合实例 .......................................... 472 聚合实例的状态展现.............................................................. 473 用例优化资源库查询 .............................................................. 474 处理不同类型的客户端 .......................................................... 474 渲染适配器以及处理用户编辑 .............................................. 475 应用服务 ......................................................................................... 478 示例应用服务 ......................................................................... 478 解耦服务输出 .........................................................................485 组合多个限界上下文 ......................................................................487 基础设施 .........................................................................................489 企业组件容器 .................................................................................490 本章小结 .........................................................................................494 附录A 聚合与事件源:A+ES ..............................................495 应用服务内部 ................................................................................. 496 命令处理器 .....................................................................................505 Lambda语法....................................................................................508 并发控制 ......................................................................................... 510 A+ES所带来的结构自由性 ............................................................. 513 性能 ................................................................................................. 513 实现事件存储 ................................................................................. 516 关系型持久化 ................................................................................. 520 BLOB持久化 .................................................................................. 522 专注的聚合 ..................................................................................... 523 读模型投射 ..................................................................................... 524 目录xvii 与聚合设计一道使用 ..................................................................... 527 增强事件 ......................................................................................... 527 工具和模式 ..................................................................................... 529 事件序列器 ............................................................................. 530 事件不变性 ............................................................................. 531 值对象 ..................................................................................... 531 协议生成 ......................................................................................... 534 单元测试和需求规范 ..................................................................... 535 事件源和函数式语言 ..................................................................... 536 参考文献 ...........................................................................539