书 · 2003-08 · 埃里克·埃文斯(Eric Evans)

《领域驱动设计》

计算机与 AI书单第 46 名

一句话结论

复杂业务软件的设计,要靠开发者与领域专家共同建立模型,并让日常语言、代码和团队边界持续围绕这个模型调整。

值不值得读完整本?

值得读完整本,尤其适合已经遇到业务规则复杂、团队沟通困难或系统改动牵一发动全身的读者;全书后半部对模型演进和战略设计的讨论,是只学几个设计模式无法替代的。

  • 先读第一至三章,弄清领域模型为什么同时承担理解业务、组织沟通和指导实现的作用,再读第七章货运案例,看看这些要求怎样落地。
  • 第四至六章细读实体、值对象、领域服务、聚合、工厂和仓储;最好选一个熟悉的业务,实际写出身份判定、业务规则和一致性边界。
  • 第八至十三章重点看隐含概念怎样进入模型,以及接口、函数和重构怎样降低理解成本;第十一、十二章涉及的具体模式,初读可略读,用到时再查。
  • 第十四至十七章不要跳过:限界上下文、核心领域和大型结构解释的是跨团队、跨模型的设计问题。读完后给自己的系统画一张上下文关系图,再判断哪些部分值得投入最多建模精力。

核心观点

1. 用共同语言一起发现业务模型

领域模型是针对当前问题提炼的概念体系,由开发者与领域专家共同形成。模型中的术语应进入讨论、文档和代码,成为通用语言。

为什么:业务专家通常掌握大量经验,却未必能直接给出适合软件实现的概念结构。开发者如果只接收功能清单,就容易把业务误解隐藏在技术实现里。双方用同一组概念推演具体场景,歧义、遗漏和矛盾才会暴露出来。不断修正语言,也就在不断修正对业务的理解;模型的价值因此取决于它能否帮助团队解释和解决实际问题。

2. 让模型与实现相互约束

指导业务理解的模型,也应实际指导软件结构;开发中的反馈则应反过来修正模型。领域逻辑需要与界面、应用协调和基础设施职责分开。

为什么:如果分析模型无法在代码中辨认,开发者就必须维护两套解释,模型很快会失去约束力。如果实现完全由数据库或框架决定,业务规则又会散落在技术细节里,变得难以讨论和修改。把领域逻辑隔离出来,可以让规则在较少干扰的环境中表达和验证。参与建模的人也要接触实现,因为代码中的困难可能说明模型本身需要改变。

3. 按身份、业务职责和一致性组织对象

实体依靠持续身份区分,值对象依靠属性含义区分;领域服务承载不适合归属于某个实体或值对象的领域操作。聚合划定一致性边界,工厂负责复杂创建,仓储提供领域对象的查找与取得。

为什么:把所有东西都当作有身份的对象,会增加无必要的跟踪和关联;把需要延续身份的事物当作普通属性集合,又会丢失业务连续性。对象关系如果无限开放,任何调用者都可能绕过规则修改内部状态。聚合通过根对象控制外部访问和修改,把必须共同维护的不变量收束到明确边界中。工厂与仓储再把创建和存储方面的复杂性移开,让业务代码集中表达对象的含义与行为。

4. 通过重构把隐含知识变成明确概念

更好的模型往往来自对已有实现的重新理解:发现原先藏在条件判断、操作流程或口头解释中的概念,再让代码围绕它们重组。柔性设计使这种演进更容易。

为什么:最初的模型通常只能覆盖团队当时看见的问题,新的场景会暴露它的局限。反复出现的判断、别扭的职责和术语冲突,可能提示某个重要概念尚未被表达。将它明确化,可以把分散的规则集中起来,让其他规则通过组合而不是复制来使用它。表达意图的接口、无副作用函数和明确的约束,又能减少修改时必须同时理解的内容,使下一轮探索更便宜。

5. 在限界上下文内统一,在边界之间协调

大型系统不必共享一个无所不包的模型,而应明确每个模型适用的限界上下文。再用上下文映射说明模型之间的关系、集成方式和团队依赖。

为什么:同一个词在不同工作中可能服务于不同目的,强行统一会把各方需求塞进越来越含糊的概念。明确边界后,每个模型可以在自己的范围内保持一致,并通过持续集成及时发现内部偏离。边界之间仍然需要翻译和协作,而选择共享内核、客户与供应方关系或防腐层,要考虑团队实际拥有的协调能力。这样既能保护模型含义,也能把集成代价摆到明处。

6. 把设计投入集中到核心领域,并让整体结构演进

战略设计要识别真正体现业务特色的核心领域,从通用功能和辅助机制中把它提炼出来。大型结构提供共同方向,但也要随着认识增长而调整。

为什么:团队的时间和优秀设计能力有限,平均投入会让关键业务与普通功能争夺同样的注意力。核心领域如果被基础设施和通用机制淹没,开发者就难以看出系统最重要的知识在哪里。精炼通过分离和突出核心,让资源优先流向最能创造业务价值的部分。大型结构则帮助各部分保持可理解的关系,但过早固定结构又会压制局部发现,所以整体秩序也必须允许演进。

反对意见

共同建模的贡献需要放回需求工程传统中看(Ian Alexander)

Alexander在书评中肯定本书重视领域知识与沟通,但追问其中一些工作是否重新发现了传统需求分析已有的知识组织方法。他还认为作者对瀑布模型缺少反馈的描述不公平,忽略了Royce原有论述中的反馈安排。这挑战的是方法的新颖性及其历史叙述,并不否定共同建模的价值。

对象结构还不足以表达用户行为(Jim Coplien)

Coplien在工作坊介绍中认为,领域驱动设计对静态结构的整理有帮助,但对用户故事、用例以及跨对象协作如何进入架构,指导仍不充分。他提出用数据、上下文与交互的分离来补充行为表达。这是对方法覆盖范围的批评与补足,不能扩大为他否定全部领域驱动设计。

数据与行为也可以分开组织(Yehonathan Sharvit)

Sharvit在《Data-Oriented Programming: Reduce Software Complexity》中主张,以通用的不可变数据结构保存状态,用独立函数处理数据,以减少数据、行为和类型结构之间的耦合。这为原书主要采用的领域对象组织方式提供了不同实现路线。它不是针对埃文斯原书的直接反驳,也不排斥共同语言和限界上下文。

相关推荐

导读由 AI 根据公开资料整理,没有读取原书全文,一切以原著为准。导读 Primer 首页