CH.01📚 书籍元信息
- 书名:《领域驱动设计:软件核心复杂性应对之道》(Domain-Driven Design: Tackling Complexity in the Heart of Software)
- 作者:Eric Evans(埃里克·埃文斯)
- 类型:软件工程 / 架构设计
- 输入类型:仅书名
- 一句话总结:这本书回答了「复杂业务系统如何避免技术与业务脱节」的问题,答案是以领域模型为核心驱动力,让软件结构映射业务本质结构。
- 适读人群:
- 最需要读的人:正在设计金融、电商、医疗、保险、ERP 等复杂业务系统的架构师与技术负责人;长期受困于"业务逻辑散落各层"问题的高级开发者。
- 反而可能被误导的人:刚学会编程的新手——DDD 的投资回报在简单场景下极低;以及纯粹的技术型系统(编译器、图形引擎、嵌入式驱动)开发者——这些系统的复杂性在技术侧而非业务侧。
CH.02🔍 真问题
核心问题:复杂业务系统开发中,如何让软件的内部结构真正反映业务领域的本质结构,而不是被技术框架、数据库表结构或团队分工所扭曲?
旧答案:在 DDD 出现之前,主流做法主要有三类:
- 数据驱动设计:先设计数据库表结构,业务逻辑围绕数据存取展开,领域知识被压缩成表的字段和关联关系。
- 贫血领域模型:表面上建了领域对象,但对象只包含数据字段(getter/setter),全部业务逻辑挤在 Service 层——看似有模型,实则无模型。
- 技术框架驱动:以 EJB、三层架构等技术约定来组织代码,结构由技术关注点决定,业务专家被排斥在设计过程之外。
- 这些做法共同的后果:业务知识碎片化地散落在 UI、Service、DAO、存储过程中,没人能看到全貌;业务专家与开发者之间存在巨大的"翻译鸿沟",信息在翻译中不断损耗。
新答案:将领域建模提升为软件开发的核心活动。让业务专家和开发团队围绕一个共享的领域模型持续协作,用模型作为沟通的基础和代码的灵魂。系统设计不是从数据库表出发、也不是从技术架构出发,而是从业务领域的概念结构出发。
答案的底层逻辑:软件的复杂性根源在业务领域本身,而非技术实现。传统方法的致命问题在于"技术倒推业务"——数据库表结构决定了领域对象的形状,技术层的划分决定了业务逻辑的归宿。DDD 的核心主张是反转这个方向:先理解业务领域的概念结构,让技术实现服务于领域模型,而非反过来。软件系统的长期可维护性取决于它能否忠实地反映业务意图。
关键边界:
- DDD 适用于复杂业务领域——业务规则多、概念关系复杂、团队协作规模大。
- 在简单 CRUD 应用或纯技术型系统中,DDD 的投入产出比极低,甚至导致过度设计。
- DDD 要求团队愿意投入持续的建模过程——如果项目节奏不允许开发人员与业务专家深入交流,DDD 难以落地。
CH.03🗺️ 知识地图
(图说明:DDD 由战略设计、战术设计、核心理念三大分支构成,从宏观到微观层层递进。)
CH.04💡 核心模型深度解析
模型一:统一语言(Ubiquitous Language)
模型定义
当业务专家与开发团队围绕同一套领域模型建立共享术语,并直接将这套术语编码进软件系统时,翻译损耗趋近为零,代码结构与业务意图保持一致。
(图说明:统一语言打通业务与技术,形成"术语→模型→代码→验证"的闭环。)
原书论证
Evans 在书中反复强调一个现象:开发团队内部使用的语言和业务专家使用的语言存在系统性偏差。比如业务说"签发提单",开发说"创建记录";业务说"预订舱位",开发说"插入订单表"。每一次"翻译"都伴随着信息损耗和语义漂移。
据作者论述,统一语言不是一份写完就归档的术语表,而是一种持续的团队纪律:当发现某个业务概念没有对应的代码表达,或代码中的概念在业务中找不到对应物时,这本身就是一个设计缺陷的信号。在书中贯穿使用的货运公司案例中,团队围绕"货物(Cargo)"这一核心概念建立的统一语言贯穿了整个设计过程。
迁移场景
跨职能产品团队:产品经理用"用户旅程"描述需求,工程师用"接口调用"理解实现,两者之间存在翻译鸿沟。建立统一语言意味着定义一套团队共享的概念(如"激活""转化""留存"的精确技术含义),并将它们写进代码命名和产品文档中。
医疗信息系统开发:临床专家说的"入院"和系统中的"创建就诊记录"并非同一概念——前者包含了分诊、床位分配、医保登记等一系列业务含义。统一语言要求开发人员真正理解每个临床术语的完整含义,而非将其压缩为一条数据库记录。
金融合规系统:合规专家说的"异常交易"和代码中的"flag=1"之间差距巨大。统一语言要求将"异常交易"拆解为可建模的业务概念(如"短时间高频交易""大额转账至境外"),每种异常类型对应明确的业务规则和检测逻辑。
失效边界
- 失效场景 1:领域本身高度不稳定——在快速迭代的创业早期,业务模式每周都在变,强行建立统一语言反而变成"把时间花在追赶变化上"。此时更需要的是快速原型验证而非精确建模。
- 失效场景 2:团队成员拒绝投入——统一语言要求开发者学习业务,要求业务专家学习技术术语。如果任何一方不愿意跨越认知边界,统一语言就退化为墙上的一张术语表。
- 失效场景 3:语言被强制但没有模型支撑——如果没有真实的领域模型作为骨架,统一语言就变成了空洞的术语约定,命名一致但结构仍然混乱。
改造方法
- 补一个变量:语言的活化机制。原书强调语言是"活的",但没有给出具体的活化机制。改造方向:建立定期的"术语校准会",当业务发生变化时同步更新领域词典。
- 替换一个前提:原书假设软件开发是主要场景。替换为"任何跨专业协作场景"。
- 改造后形式:团队共识协议——一套由跨职能团队共同维护的领域词典 + 命名规范 + 迭代校准机制,不局限于软件代码。
行动接口(3 套 SOP)
🟢 小白版 SOP(第一次用这个模型的人)
- 触发条件:你发现开发人员和业务人员在会议上各说各话,同一个词在不同人口中有不同含义。
- 执行步骤:
- 选择一个当前项目中最核心的业务概念(如"订单""客户""合同")。
- 把开发团队和业务专家拉到一起,用一小时讨论:这个概念到底包含哪些属性和行为?它在业务流程中何时产生、何时变化、何时消亡?
- 将讨论结果写成一段"概念定义",包含:名称、核心属性、核心行为、生命周期。
- 用这个定义中的术语命名代码中的类和方法——不再使用技术化的命名(如 "createRecord" → "签发提单")。
- 在后续每次迭代中检查:有没有代码中的概念在业务中找不到对应?有没有业务术语在代码中没有体现?有则修正。
- 验证标准:业务专家能看懂代码中的核心领域类的命名和结构。
- 回滚机制:如果团队抵触强烈,退回到"核心概念文档"阶段,不强制命名,但保留术语对照表。
🟡 老手版 SOP(已掌握基础想用得更深)
- 触发条件:你已经为项目建立了初步的统一语言,但发现语言在不同子系统间出现了分叉。
- 执行步骤:
- 盘点当前所有子系统/模块中的领域概念命名,找出不一致之处(如同一个概念在 A 模块叫 "Product",在 B 模块叫 "Item")。
- 按限界上下文归类:哪些不一致是因为同一个上下文中的命名混乱(需要统一)?哪些是因为不同上下文中的合法差异(需要保留并标注边界)?
- 在代码仓库中建立
domain/目录,将核心领域概念的定义(含代码注释)集中管理。 - 建立持续集成检查:核心领域概念的命名变更必须经过领域评审。
- 验证标准:新增开发者阅读
domain/目录后,能准确描述业务的核心概念。 - 常见进阶陷阱:把统一语言做成了"中央集权式命名管理"——所有命名变更都要经过一个人审批,结果语言演进速度跟不上业务变化。
🔵 团队版 SOP(嵌入团队工作流)
- 触发条件:团队规模超过 5 人,且有多个子系统需要集成。
- 角色 × 步骤矩阵:
- 业务专家(负责):参与领域建模工作坊,审阅领域概念定义,验证模型是否反映业务真实意图。
- 技术负责人(负责):将统一语言映射到代码结构,确保命名一致性。
- 产品经理(负责):在需求文档中使用统一语言,不再发明新术语。
- QA(负责):在测试用例中使用统一语言描述业务场景。
- 全员(对齐):每两周一次"术语校准"(15 分钟),快速解决发现的术语冲突。
- 验证标准:需求评审会上,所有人使用相同术语讨论同一个概念,不需要额外解释。
- 回滚机制:如果术语校准会流于形式,退回到"核心概念文档 + PR 中的命名检查"模式。
决策检查清单
- 项目中的核心业务概念是否在代码和文档中有一致的命名?
- 业务专家能否看懂核心领域代码的命名和结构?
- 是否存在技术术语(如"记录""对象""表")被当作业务术语使用?
- 当业务概念发生变化时,代码和术语是否同步更新?
- 新成员加入时,是否有渠道了解项目的统一语言?
内容种子
- 可衍生文章选题:「为什么你的代码里没有一个业务名词?——统一语言的反面教材」
- 可设计课程模块:「领域建模实战工作坊:从混乱术语到统一语言」
- 可提出咨询问题:「你的团队中,开发和业务对核心概念的理解一致吗?」
批判刃(三类批判)
前提批
- 隐含前提 1:存在可以被精确定义的领域概念。但在某些领域(如创意工作、社会科学研究),概念本身就是模糊和多义的,强行统一反而遮蔽了领域的丰富性。
- 隐含前提 2:业务专家愿意且能够深度参与建模过程。在很多组织中,业务专家的时间极其稀缺,他们无法持续投入。
内部批
- 内部漏洞:统一语言的"正确性"由谁判定?作者强调语言要在团队协作中自然演化,但没有给出解决命名冲突的决策机制——当业务方和技术方对某个术语的定义产生根本分歧时,谁说了算?
- 已知反例:某些成功的大规模系统(如早期的 Amazon)在快速发展阶段并未刻意推行统一语言,而是依靠微服务架构的事后拆分来解决概念不一致问题。
适用范围批
- 有效边界:统一语言在概念清晰、业务相对稳定的领域(如金融交易、物流管理)效果最好。在探索性业务(如社交产品功能迭代)中,概念本身尚未稳定,统一语言的维护成本可能超过收益。
- 执行成本:全员学习领域知识 + 定期校准会 + 代码命名重构 = 显著的时间投入。对于交付压力大的项目,这个成本可能被直接跳过。
模型二:限界上下文(Bounded Context)
模型定义
当为每个领域子模型划定明确的概念边界时,边界内可以保持术语一致性和模型纯度,而不同边界之间同一个术语可以有不同含义——模型的有效性被约束在边界之内。
(图说明:同名的"产品"在三个限界上下文中各有不同属性,不能强行统一。)
原书论证
据作者论述,当一个系统变得复杂时,最自然的做法是试图建立一个"统一的企业模型",让所有部门共享。但这恰恰是灾难的开始——销售眼中的"客户"包含偏好、联系方式和营销标签,而财务眼中的"客户"包含信用等级、账期和发票信息。强行统一这些概念会让模型变得臃肿、妥协,每个人都不满意。
Evans 以货运公司案例说明:在"预订上下文"中,"货物"关注的是航线、舱位和运费;在"运输上下文"中,"货物"关注的是当前位置、温度和运输状态。这不是同一概念,而是同名概念在不同语境中的不同投影。
限界上下文的另一个深刻洞察是与团队边界的对应关系——据作者论述,上下文的边界往往与组织的团队边界自然吻合。这与康威定律(组织结构决定系统架构)形成了呼应。
迁移场景
微服务拆分决策:限界上下文是微服务拆分的核心指导原则。不是按技术层拆(前端/后端/数据库),也不是按功能模块粗暴拆,而是按业务概念的边界来拆。每个微服务对应一个限界上下文,内部保持模型一致,外部通过 API 交互。
组织架构设计:当企业规模扩大时,不同部门对同一个业务术语有不同理解是正常的——这不是沟通问题,而是不同工作语境的自然结果。限界上下文的思维方式帮助管理者接受这种差异,而不是强制统一。
知识管理体系:一个企业的知识库如果试图用一套统一的分类体系管理所有知识(销售知识、技术知识、法务知识),结果往往是分类混乱。限界上下文思维意味着为不同知识域建立独立的知识空间,各有各的分类逻辑。
失效边界
- 失效场景 1:过度拆分——当限界上下文拆得太细,上下文间的集成成本会爆炸。一个请求需要穿越五个上下文才能完成,每个上下文都有自己的数据复制和转换逻辑,系统变得比"大一统"更难维护。
- 失效场景 2:需要跨上下文强一致性时——限界上下文的前提是上下文之间可以最终一致性。但在某些场景(如金融核心交易),跨上下文强一致性是刚需,此时限界上下文的边界变成了障碍。
- 反例:一些成功的单体应用(如早期的 Shopify)通过模块化的代码组织实现了类似限界上下文的效果,但并未在部署层面拆分——说明限界上下文的思维价值不一定要通过微服务物理拆分来实现。
改造方法
- 补一个变量:沟通密度。原书侧重模型边界,较少讨论上下文之间需要多高频率的沟通。改造方向:增加"上下文间沟通带宽"变量,根据实际沟通频率决定上下文的粒度。
- 替换一个前提:原书假设上下文由同一组织内团队负责。替换为"跨组织协作"场景。
- 改造后形式:上下文矩阵——每个上下文标注其模型所有者、消费者、集成频率和变更速率,作为架构决策的输入。
行动接口(3 套 SOP)
🟢 小白版 SOP
- 触发条件:你发现项目中同一个业务概念在不同模块中有不同的定义和行为,修改一处导致另一处出错。
- 执行步骤:
- 列出系统中所有核心业务概念(如"产品""订单""客户")。
- 在每个模块中检查:这个概念在这个模块里包含哪些属性和行为?与其它模块的定义是否一致?
- 将定义一致的模块归为一组,将定义不同的模块拆分开来。
- 对于拆分后有重叠的概念,为每个上下文赋予不同的名称或在名称前加限定词(如"销售产品"vs"库存产品")。
- 在上下文之间建立明确的接口(API 或事件),而非共享数据库。
- 验证标准:修改一个上下文内部的模型不会导致另一个上下文的编译错误或逻辑异常。
- 回滚机制:如果拆分导致集成复杂度过高,将部分上下文合并为"共享内核",明确标注共享的边界。
🟡 老手版 SOP
- 触发条件:你正在设计一个新系统,需要决定整体的上下文划分策略。
- 执行步骤:
- 画出业务流程全景图,标注每个业务环节涉及的核心概念。
- 按"概念一致性"而非"功能相似性"归类:如果两个功能对同一个概念的处理逻辑相同,放在一个上下文中;如果不同,拆开。
- 评估每个上下文的团队归属——理想情况下,一个上下文由一个全功能团队全权负责。
- 绘制上下文地图,标注上下文间的集成模式(参见模型四:上下文映射)。
- 对核心上下文投入最好的开发资源,对通用上下文(如通知、报表)寻找现成方案。
- 验证标准:每个上下文可以用一句话描述其业务职责,且不与其它上下文的描述冲突。
- 常见进阶陷阱:把限界上下文等同于"技术模块"——按数据库表分、按 UI 页面分,而非按业务概念分。
🔵 团队版 SOP
- 触发条件:组织正在从单体架构向分布式架构迁移。
- 角色 × 步骤矩阵:
- 架构师(负责):主持上下文划分研讨会,输出上下文地图。
- 各业务负责人(负责):确认自己团队管辖的业务域与哪个上下文对应。
- 技术负责人(负责):评估上下文间的集成复杂度和技术可行性。
- 项目管理(负责):按上下文划分团队职责和交付节奏。
- 全员(对齐):每季度回顾一次上下文划分是否仍然合理——随着业务变化,上下文边界可能需要调整。
- 验证标准:每个团队能清晰回答"我负责哪个上下文,我的上下文与其他上下文的边界在哪里"。
- 回滚机制:如果上下文拆分后团队协作效率严重下降,临时建立"跨上下文协调员"角色,同步推进模型对齐。
决策检查清单
- 系统中的核心业务概念是否只有一个权威定义?
- 修改一个业务概念时,是否只需要在一个地方改?
- 上下文之间的集成方式是 API/事件还是共享数据库?
- 上下文的边界是否与团队的职责边界对齐?
- 是否存在"上帝模型"——一个概念承载了所有业务的全部属性?
内容种子
- 可衍生文章选题:「你不需要一个统一的"客户"模型——限界上下文的设计哲学」
- 可设计课程模块:「从单体到微服务:限界上下文驱动的拆分策略」
- 可提出咨询问题:「你的企业中,同一个术语在不同部门的含义差异有多大?」
模型三:聚合(Aggregate)
模型定义
当将一组相关对象封装为以聚合根(Aggregate Root)为唯一入口的一致性单元时,数据修改的不变量(invariant)得以在事务边界内保证——聚合是变更操作的原子单位。
(图说明:聚合通过根实体管控内部一致性,外部只能通过聚合根访问或通过ID间接引用。)
原书论证
据作者论述,复杂领域中的对象图盘根错节,如果不加限制地允许任意对象之间的直接引用和修改,会导致两个致命问题:一是事务范围无法控制——修改一个对象可能级联触发十个对象的变更;二是并发冲突无法管理——多人同时修改同一个对象图的不同部分时,冲突范围不可预测。
聚合通过划定一个"一致性不变量的边界"来解决这个问题。以订单为例:订单总价必须等于所有行项金额之和——这是一个不变量。如果订单和行项不在同一个聚合中,修改行项金额时就无法同时更新订单总价,数据一致性就会被打破。
Evans 提出的关键设计原则是:聚合之间通过 ID 引用而非直接对象引用。订单只存客户 ID,不存客户对象;只存商品 ID,不存商品详情。这使得每个聚合可以被独立地加载、修改和持久化,大幅降低了系统的复杂性。
迁移场景
数据库事务边界设计:聚合的边界直接映射为数据库事务的边界。一个事务修改一个聚合内的所有对象,保证不变量;跨聚合的修改通过最终一致性或领域事件来协调。
分布式系统数据一致性:在微服务架构中,聚合是服务内部数据一致性的最小单元。一个微服务可以包含多个聚合,但每个聚合的修改在服务内是事务性的,跨服务的修改通过 Saga 或事件驱动实现。
并发控制策略:聚合根的版本号可以作为乐观锁的依据——对同一个聚合的并发修改会被检测并处理,而不同聚合之间的操作不需要加锁,最大化并发性能。
失效边界
- 失效场景 1:聚合过大——当聚合包含过多对象时,加载和修改整个聚合的代价变得不可接受。比如把"公司"作为聚合根,包含所有部门、员工、合同,每次修改任何东西都要锁定整个公司对象图。
- 失效场景 2:跨聚合强一致性需求——当业务要求两个聚合的修改必须是原子性的(如"扣款成功且发货成功",两者必须同时成功或同时失败),聚合的隔离性就变成了障碍。这需要 Saga 等更复杂的补偿机制。
- 失效场景 3:聚合边界识别错误——把本应属于同一聚合的对象拆到了不同聚合中,导致不变量无法在单个事务内保证。
改造方法
- 补一个变量:聚合的一致性等级。不是所有不变量都需要事务性保证。改造方向:为每个聚合标注一致性等级(强一致 / 最终一致 / 可容忍短暂不一致),据此选择不同的实现策略。
- 改造后形式:分级聚合——强一致聚合用事务保证,最终一致聚合用领域事件协调,可容忍不一致聚合用异步更新。
*行动接口(3 套 SOP)
🟢 小白版 SOP
- 触发条件:你发现数据库中修改一个业务对象时,需要同时修改多个关联表,否则数据会不一致。
- 执行步骤:
- 找到需要保持一致性的那组数据——哪些字段必须同时正确?
- 将这组数据定义为一个聚合,选一个"入口"对象作为聚合根。
- 确保所有对这组数据的修改都通过聚合根进行,禁止外部直接修改内部对象。
- 将聚合根作为数据库事务的操作单元——一个事务只修改一个聚合。
- 对于需要引用但不属于本聚合的对象,只存其 ID。
- 验证标准:单个聚合的修改总能在单个事务内完成。
- 回滚机制:如果聚合太大导致性能问题,识别其中变更频率不同的部分,将其拆分为多个小聚合。
🟡 老手版 SOP
- 触发条件:你正在设计新功能,涉及多个关联对象的变更。
- 执行步骤:
- 分析业务不变量:哪些约束是跨对象的?(如"订单总额 = 行项金额之和")
- 将每个不变量归属到一个聚合中——聚合的职责是保证该不变量。
- 评估聚合的大小和变更频率——如果聚合过大,拆分后不变量是否仍然可以保证?
- 对于跨聚合的一致性需求,设计领域事件或 Saga 来协调。
- 为每个聚合定义接口方法——方法名使用统一语言(如"签发提单"而非"updateStatus")。
- 验证标准:每个聚合的接口方法都对应一个明确的业务操作,每个不变量都有且仅有一个聚合负责维护。
- 常见进阶陷阱:把聚合当成了"数据库分表依据"——聚合是领域概念,不是数据存储概念。
🔵 团队版 SOP
- 触发条件:团队需要对现有系统的数据一致性问题进行系统性梳理。
- 角色 × 步骤矩阵:
- 架构师(负责):定义聚合划分原则,审核聚合设计。
- 开发人员(负责):按聚合原则重构代码,确保修改通过聚合根进行。
- DBA(负责):评估聚合划分对数据库事务和性能的影响。
- 测试(负责):针对每个聚合编写一致性测试用例。
- 全员(对齐):建立"聚合变更通知"机制——修改聚合的接口必须通知所有相关方。
- 验证标准:所有数据库事务的范围都能映射到单个聚合,跨聚合一致性通过明确的机制(事件/Saga)保证。
- 回滚机制:如果聚合重构导致事务性能下降,评估是否需要将部分"强一致"需求降级为"最终一致"。
决策检查清单
- 每个聚合是否有且仅有一个聚合根?
- 聚合间的引用是否通过 ID 而非直接对象引用?
- 每个不变量是否归属到唯一一个聚合?
- 聚合的大小是否可控(加载时间可接受)?
- 跨聚合的一致性需求是否有明确的处理机制?
内容种子
- 可衍生文章选题:「你的聚合太大了——DDD 中最常见的设计错误」
- 可设计课程模块:「聚合设计实战:从业务不变量到代码边界」
- 可提出咨询问题:「你的系统中,哪些数据修改操作需要跨多个数据库表?它们能否归入同一个聚合?」
批判刃(三类批判)
前提批
- 隐含前提 1:业务不变量可以被清晰识别和形式化。但在很多业务中,"一致性"是模糊的(如"库存扣减和订单创建应该同时成功"在实际中可以有秒级延迟)。
- 隐含前提 2:聚合的大小和边界可以被相对稳定地确定。但业务需求持续变化时,聚合边界也在不断移动,重构成本被低估了。
内部批
- 内部漏洞:Evans 强调聚合之间通过 ID 引用来降低耦合,但 ID 引用并不等同于真正的解耦——如果一个聚合的 ID 在另一个聚合中被大量使用,ID 的变更仍然是全局性的。
- 已知反例:在事件溯源(Event Sourcing)架构中,聚合的概念被重新定义为"事件流的根",持久化和一致性模型与传统聚合完全不同,说明聚合的概念有较强的范式依赖。
适用范围批
- 有效边界:聚合最适合事务性业务系统(金融、电商、ERP)。在分析型系统(BI、数据仓库)或流处理系统中,聚合的概念几乎不适用。
- 执行成本:正确识别聚合边界需要深度领域知识 + 大量迭代——这是一次性成本还是持续成本被严重低估。
- 隐藏代价:作者强调了聚合带来的设计清晰度,但较少讨论聚合划分不当导致的连锁重构成本——如果错误地划分了一个核心聚合,所有引用它的模块都要改。
模型四:上下文映射(Context Mapping)
模型定义
当识别出不同限界上下文之间的权力关系、依赖方向和集成需求后,选择匹配的协作模式(如防腐层、开放主机服务、客户-供应商等),可以最小化上下文间的耦合,使集成变得可控。
(图说明:不同上下文间选择不同的协作模式,取决于权力关系和集成需求。)
原书论证
Evans 列举了多种上下文间映射模式,每种对应不同的协作关系:
- 合作关系(Partnership):两个上下文的团队紧密协作,共同演进模型。
- 共享内核(Shared Kernel):两个上下文共享一部分模型定义,修改共享部分需要双方同意。
- 客户-供应商(Customer-Supplier):下游(客户)向上游(供应商)提出需求,上游有优先权但需要考虑下游需求。
- 跟随者(Conformist):下游完全接受上游的模型,不做任何转换。
- 防腐层(Anti-Corruption Layer):下游建立一层转换层,将上游的模型翻译为自己的模型,保护自己不受上游变化的影响。
- 开放主机服务(Open Host Service):上游提供标准化的协议和文档,供多个下游接入。
- 各行其道(Separate Ways):两个上下文完全独立,不做集成。
据作者论述,选择哪种模式不是技术决策,而是权力关系和业务关系的反映。防腐层常用于对接遗留系统——你无法改变遗留系统的模型,但可以保护新系统不被其污染。
迁移场景
企业并购后的系统整合:两家公司合并后,各自的 IT 系统需要对接。用上下文映射思维:在整合初期为每个系统建立防腐层,逐步向共享内核或开放主机服务演进,避免"强行统一模型"的灾难。
第三方系统对接:你的系统需要对接外部 API(如支付网关、物流系统)。上下文映射帮助你决定:是直接用外部系统的模型(跟随者),还是建一层适配器(防腐层)?
跨团队协作模式设计:两个团队需要共享某些能力。上下文映射帮助你决定:是建立共享内核(共同维护一套代码),还是通过 API 松耦合集成(客户-供应商)?
失效边界
- 失效场景 1:权力关系不明确——当两个上下文的团队在组织中地位对等,客户-供应商模式无法自然形成,需要额外的治理机制。
- 失效场景 2:映射模式固化——组织架构变化后,上下文间的协作模式可能需要调整,但如果模式被固化在代码中(如硬编码的防腐层),调整成本很高。
- 反例:Netflix 等公司通过统一的 API 网关和服务网格实现了高度标准化的上下文间通信,实际上消解了"选择哪种映射模式"的需要——基础设施层面的标准化替代了领域层面的模式选择。
改造方法
- 补一个变量:上下文间变更频率。原书的模式选择主要基于权力关系,较少讨论变更频率的影响。改造方向:高频变更的上下文间用防腐层隔离,低频变更的上下文间可以共享内核。
- 改造后形式:动态映射策略——根据上下文间的耦合度、变更频率和团队关系,动态选择和调整映射模式。
行动接口(3 套 SOP)
🟢 小白版 SOP
- 触发条件:你的系统需要与另一个系统(遗留系统、第三方系统、其他团队的系统)集成。
- 执行步骤:
- 分析对方系统的模型与你的模型之间的差异。
- 评估你的团队是否有能力影响对方的模型设计。
- 如果无法影响对方(如遗留系统),建立防腐层——写一个适配层,将对方的数据结构翻译为你的领域模型。
- 如果可以协商(如合作伙伴系统),建立明确的 API 契约,定义各自的职责。
- 将集成逻辑与核心领域逻辑分离——集成层可以随时替换,核心领域不受影响。
- 验证标准:当对方系统变更 API 时,只需修改适配层,核心领域代码无需改动。
- 回滚机制:如果防腐层过于复杂,评估是否可以直接跟随对方模型(Conformist)。
🟡 老手版 SOP
- 触发条件:你需要为整个企业系统绘制上下文地图。
- 执行步骤:
- 盘点所有限界上下文及其团队归属。
- 分析每对上下文间的关系:谁依赖谁?谁提需求谁响应?变更影响方向?
- 为每对上下文选择映射模式,画出完整的上下文地图。
- 识别地图中的"枢纽上下文"——被最多上下文依赖的上下文,对其稳定性要求最高。
- 定期审视上下文地图——组织架构调整后,映射模式可能需要重新选择。
- 验证标准:任何两个上下文间的技术集成方案都能在上下文地图中找到对应的映射模式。
- 常见进阶陷阱:试图用一种映射模式解决所有集成问题——实际上不同上下文对应该用不同模式。
🔵 团队版 SOP
- 触发条件:多团队需要协作交付一个跨上下文的业务功能。
- 角色 × 步骤矩阵:
- 架构师(负责):绘制上下文地图,确定映射模式。
- 各上下文负责人(负责):明确自己上下文的 API 契约和变更影响范围。
- 集成团队(负责):实现和维护上下文间的适配层。
- PM(负责):在需求评审中标注涉及哪些上下文,评估集成成本。
- 全员(对齐):上下文间的集成问题升级为"架构决策"而非"技术问题"。
- 验证标准:新增一个跨上下文的功能时,团队能在一天内识别出需要修改哪些映射点。
- 回滚机制:如果集成复杂度失控,暂停新增跨上下文功能,先清理现有映射关系。
决策检查清单
- 每个上下文间的集成方式是否明确标注了映射模式?
- 对方系统变更时,你是否只需要修改适配层?
- 是否存在"隐式耦合"——没有通过 API 而是通过共享数据库产生的依赖?
- 组织架构调整后,上下文地图是否同步更新?
- 跨上下文的数据流是否有单向的依赖关系(避免循环依赖)?
内容种子
- 可衍生文章选题:「防腐层是你的系统免疫系统——为什么集成不等于合并」
- 可设计课程模块:「企业系统集成:从上下文地图到技术方案」
- 可提出咨询问题:「你的系统与外部系统之间是何种关系?当前的集成策略是否匹配?」
模型五:领域精炼(Domain Distillation)
模型定义
当识别出核心域、支撑域和通用域的分类后,将最优秀的人力和智力资源集中在核心域——差异化的真正来源——而对通用域采用现成方案或最低成本实现,从而实现资源的最优配置。
(图说明:按业务差异化和领域复杂度两个维度,决定对各子域的投入策略。)
原书论证
据作者论述,不是所有业务子域都同等重要。一个电商系统的核心竞争力可能在于"推荐算法"和"供应链管理",而"用户认证""邮件通知"虽然必需,但不构成差异化优势。DDD 的领域精炼要求团队识别出这个优先级,将最好的开发人员和最多的思考时间投入到核心域。
Evans 提出了三种子域类型:
- 核心域(Core Domain):业务的核心竞争力,差异化来源,必须用最好的团队、最精心的设计。
- 支撑域(Supporting Subdomain):业务必需但不构成竞争优势,可以用标准方式实现,不必投入顶尖人才。
- 通用域(Generic Subdomain):许多企业都有类似需求,可以用开源方案或商业产品替代(如认证、消息队列、工作流引擎)。
迁移场景
企业战略资源配置:不是每个业务线都值得投入同样多的顶尖人才。核心业务线配备最强团队,非核心业务线可以用更经济的方式解决。
IT 预算分配:技术投资应该集中在核心域。把预算花在自研一个通用的消息队列上,不如直接使用 Kafka——省下的资源投入到真正的差异化能力建设上。
外包决策:哪些子域适合外包?答案是支撑域和通用域。核心域绝不能外包——它承载着你的核心竞争力和领域知识。
失效边界
- 失效场景 1:核心域识别错误——把支撑域误判为核心域,投入大量资源却未产生差异化价值。或者反过来,低估了某个领域的重要性,用通用方案应对,后来发现它是真正的竞争壁垒。
- 失效场景 2:核心域随时间漂移——今天的支撑域可能成为明天的核心域。如果资源分配固化,无法及时调整,就会错失战略机会。
- 反例:Apple 的芯片设计从"支撑域"(最初只是优化供应链的手段)演变为"核心域"(Apple Silicon 成为核心竞争壁垒),说明子域分类不是静态的。
改造方法
- 补一个变量:市场演变速度。在快速变化的市场中,核心域可能快速转移。改造方向:定期重新评估核心域,建立"战略审视"机制。
- 改造后形式:动态领域精炼——每半年重新审视子域分类,对"可能晋升为核心域的支撑域"提前投资。
行动接口(3 套 SOP)
🟢 小白版 SOP
- 触发条件:团队资源有限,需要决定在哪些地方投入最好的开发人员。
- 执行步骤:
- 列出系统中所有业务子域(如:用户管理、订单处理、支付、物流、报表、通知等)。
- 逐一回答:这个子域是否构成我们的业务差异化?是否是我们的核心竞争力来源?
- 将子域分为三类:核心域(差异化来源)、支撑域(必需但非核心)、通用域(到处都有)。
- 为核心域安排最有经验的开发者,投入最多的设计时间。
- 对通用域直接使用开源或商业方案,不再自研。
- 验证标准:团队 70% 以上的创造性工作时间花在核心域上。
- 回滚机制:如果核心域判断有误,至少通用域的选择(如开源组件)不会造成太大损失。
🟡 老手版 SOP
- 触发条件:你正在主导一个大型系统的架构重构。
- 执行步骤:
- 画出系统的子域全景图,标注每个子域的战略重要性和技术复杂度。
- 对核心域进行"深度精炼"——识别核心域中的核心概念(核心域中的核心域),这往往只有一两个关键业务概念。
- 为核心域建立独立的限界上下文和最优的上下文映射策略。
- 对支撑域选择"够用就好"的实现策略——不过度设计,但保证可维护。
- 对通用域做技术选型评估(开源 vs 商业 vs 自研),优先选择成熟方案。
- 验证标准:核心域的代码质量和模型精度明显高于支撑域和通用域,这种差异是刻意的资源分配结果。
- 常见进阶陷阱:把核心域精炼做成了"技术炫技"——核心域需要的是深度的业务理解,不是复杂的技术方案。
🔵 团队版 SOP
- 触发条件:组织年度技术规划,需要分配研发资源。
- 角色 × 步骤矩阵:
- CTO/技术VP(负责):主导子域分类讨论,与业务负责人共同确定核心域。
- 架构师(负责):评估各子域的技术复杂度,提出实现策略建议。
- 业务负责人(负责):确认各子域的战略重要性和差异化程度。
- HR(负责):根据子域分类调整人才配置——核心域配备最强团队。
- 全员(对齐):理解为什么有些子域投入多、有些投入少,减少"不患寡而患不均"的内部摩擦。
- 验证标准:核心域的技术债明显少于非核心域,核心域的人员流动率低于非核心域(说明核心岗位更有吸引力)。
- 回滚机制:如果核心域分类引发内部争议,先以"试行"方式分配资源,半年后根据效果重新评估。
决策检查清单
- 你的系统中,哪些子域构成真正的业务差异化?
- 你是否在通用域上自研了现成方案能解决的问题?
- 核心域是否配备了最优秀的开发人员?
- 是否定期(如半年一次)重新评估子域分类?
- 核心域的领域知识是否集中掌握在少数关键人身上(知识集中度风险)?
内容种子
- 可衍生文章选题:「你的技术债其实在通用域——把好钢用在刀刃上」
- 可设计课程模块:「领域精炼实战:识别核心域与战略资源分配」
- 可提出咨询问题:「你的团队 70% 的创造力花在了哪里?那是不是你的核心竞争力?」
批判刃(三类批判)
前提批
- 隐含前提 1:核心域可以被客观识别。但"什么构成差异化"本身是一个主观判断,不同的人对业务竞争力的理解不同,可能低估某些领域的战略价值。
- 隐含前提 2:资源分配可以按子域分类灵活调整。但在很多组织中,人员和预算是按部门/项目分配的,不是按"子域"分配的,调整资源分配涉及组织变革。
内部批
- 内部漏洞:Evans 提出的三种子域分类是离散的(核心/支撑/通用),但现实中存在大量"灰色地带"——某个子域可能是 60% 核心 + 40% 通用,如何处理?
- 已知反例:很多初创企业没有条件做领域精炼——全员都在做所有事,根本没有"精挑细选投入核心域"的奢侈。领域精炼更像是中大型成熟组织的工具。
适用范围批
- 有效边界:领域精炼在业务模式已经相对清晰的中大型组织中效果最好。在业务模式尚未验证的初创期,"核心域"本身还在不断试错中。
- 执行成本:需要业务战略层面的判断力,这不是纯技术团队能做到的——需要 CTO 级别的人与业务负责人共同决策。
- 隐藏代价:过度强调核心域可能导致支撑域被忽视,而支撑域的薄弱反过来会影响核心域的体验(如核心功能很好但认证流程极其难用)。
CH.05🧠 费曼检验
情境问题
情境:你是一家保险科技公司的技术负责人。公司正在开发一个智能核保系统,团队有 20 名开发者。目前系统的核心功能是"根据客户资料自动计算风险评分并给出核保建议"。业务负责人告诉你,核心竞争力在于"风险评估模型的准确性"。但你也发现以下问题:1)"客户资料"在销售系统和核保系统中的定义完全不同;2)核保规则散落在数据库存储过程、后端 Service 和前端 JavaScript 中;3)公司最近收购了一家小型再保险公司,需要整合其遗留系统。
请用本书的模型分析这个情境,提出你的架构策略。
参考解法框架:
综合运用多个模型来分析:
- 领域精炼:识别出"风险评估模型"是核心域(差异化来源),"客户资料管理"和"核保流程"是支撑域,"认证""通知""报表"是通用域。将最好的开发者集中在风险评估模型上。
- 限界上下文:"客户资料"在销售上下文和核保上下文中定义不同是正常的,应该接受这种差异而非强行统一。为销售和核保建立独立的限界上下文。
- 聚合:核保规则散落在三层架构中是典型的贫血模型问题,需要将规则逻辑内聚到领域模型中。核保上下文中的核心聚合可能是"核保申请",包含风险评分、规则匹配结果和最终建议。
- 上下文映射:收购的再保险公司遗留系统需要用防腐层对接,保护新系统不被遗留系统的模型污染。
- 统一语言:建立核保领域的统一语言——"风险评分""核保建议""拒保条件"等概念需要业务专家和技术团队共同定义。
好的回答应包含的要素:
- 能识别出核心域并据此分配资源
- 能接受"客户资料"在不同上下文中有不同定义
- 能发现贫血模型问题并提出重构方向
- 能为遗留系统整合选择合适的映射模式(防腐层)
- 能认识到统一语言是所有这些工作的基础
5 个常见误解
误解:DDD 就是微服务。 澄清:DDD 是一套设计思想,微服务只是其可能的实现方式之一。你可以在单体应用中使用 DDD(聚合、限界上下文等概念依然有效),也可以不用 DDD 来做微服务(但通常效果不好)。DDD 早于微服务概念十几年。
误解:DDD 的核心是画 UML 图。 澄清:DDD 的核心是思维模型的转变——从技术驱动转为领域驱动。UML 或任何建模工具只是表达手段。很多团队画了大量的类图和序列图,但模型与业务严重脱节,这恰恰违背了 DDD 的精神。
误解:DDD 要求一开始就建立完美的领域模型。 澄清:DDD 是迭代式建模。Evans 反复强调"模型是不完美的",需要在持续的开发和反馈中不断精炼。试图"一次做对"本身就是反 DDD 的——重要的是建立模型演化的机制。
误解:DDD 适用于所有项目。 澄清:DDD 有明确的适用边界——复杂业务领域。对于简单 CRUD 应用、纯技术型系统、早期探索型项目,DDD 的投入产出比很低。用 DDD 做一个博客系统是典型的过度设计。
误解:DDD 是架构师的工作,开发人员只需要执行。 澄清:DDD 的核心——统一语言和领域建模——必须由业务专家和开发人员共同完成。如果架构师独自设计模型然后交给团队实现,就回到了"翻译鸿沟"的老问题。DDD 是一种团队协作方式,不是一个架构方案。
12 岁孩子版
第一件事:这本书在讲怎么让电脑程序真正理解业务是怎么运转的。 第二件事:以前程序员写程序,只管技术怎么实现,不太关心业务到底是什么样的,结果写出来的东西经常和业务人员想的不一样。 第三件事:所以这本书说,写程序之前,要先和做业务的人一起搞清楚业务是什么样的,然后用一套大家都能听懂的话来描述,最后让程序的结构和业务的结构长得一样。 第四件事:你可以在写任何程序的时候用这个方法——先画清楚业务的边界,再决定程序怎么写。 第五件事:但要注意,只有复杂的业务才需要这样做,简单的小程序用这个方法反而是浪费时间。
CH.06📝 全书评估
真正解决了什么问题?:解决的是"软件系统与业务领域脱节"这个根因性问题。不是某个具体的技术 bug,而是一种系统性的设计思维缺陷——技术倒推业务。
核心模型原创性如何?:极高。限界上下文、上下文映射、聚合等概念在 DDD 之前没有被系统性地提出和命名。虽然面向对象设计、领域建模等概念更早就有,但 Evans 的贡献在于将它们组织成一套完整的战略+战术设计体系。这本书开创了一个领域。
证据质量如何?:以思想实验和案例分析为主,缺乏大规模的实证研究。书中的货运公司案例贯穿始终,展示了模型演化的思考过程,但不是来自真实项目的数据。这既是优点(清晰展示思维过程),也是局限(缺乏实证支撑)。
最大盲区是什么?:对组织和人的因素讨论不够深入。DDD 假设团队愿意且能够深度参与领域建模,但在现实中,组织政治、团队能力差异、业务专家的时间限制等都是重大障碍。Vaughn Vernon 的《实现领域驱动设计》在一定程度上弥补了这个空白。
书籍坐标:
- 同类书坐标系中,DDD 是战略设计层面的开山之作。Martin Fowler 的《企业应用架构模式》提供了战术层面的模式库,DDD 将其提升到了战略层面。Chris Richardson 的《微服务架构设计模式》是 DDD 在微服务领域的落地延伸。Vaughn Vernon 的《实现领域驱动设计》是 DDD 的实操指南。四本书形成从理念到实践的完整链条。
CH.07🔗 跨书关联
与《企业应用架构模式》(Martin Fowler)的关联
- 共振点:两本书在「如何为复杂业务系统设计良好的内部结构」问题上给出了互补的回答。Fowler 的模式库(Repository、Unit of Work、Domain Event 等)是 DDD 战术设计的基础设施层,DDD 的聚合和领域事件概念与 Fowler 的模式直接对应。
- 冲突点:Fowler 更偏向「技术模式」视角——给出可直接复用的代码结构。DDD 更偏向「业务视角」——要求从业务领域出发设计模型。如果只用 Fowler 的模式而不做领域建模,容易退化为贫血模型。
- 为什么接着读:读完 DDD 后读 Fowler,能在战术层面获得大量可直接使用的模式,将 DDD 的设计理念落地为具体的代码结构。特别是 Repository、Unit of Work、Domain Event 等模式,是实现聚合和限界上下文的关键技术手段。
与《实现领域驱动设计》(Vaughn Vernon)的关联
- 共振点:Vernon 的书是对 DDD 战术设计部分的深度展开。在聚合设计、领域事件、CQRS 等方面给出了大量实操指南和代码示例,弥补了 Evans 原书在"怎么做"层面的不足。
- 冲突点:Vernon 对聚合提出了更激进的建议(如"聚合要尽量小""优先使用值对象"),与 Evans 原书的聚合建议有所不同。Evans 的聚合概念更宽泛,Vernon 的更严格。
- 为什么接着读:DDD 原书在理念层面非常强大,但在战术实操层面留有大量空白。Vernon 的书填补了这些空白,是 DDD 落地的实操手册。
与《微服务架构设计模式》(Chris Richardson)的关联
- 共振点: Richardson 将 DDD 的限界上下文直接映射为微服务的边界,将上下文映射模式映射为微服务间的通信模式。DDD 是微服务拆分的理论基础。
- 冲突点:Richardson 更强调分布式系统的技术挑战(数据一致性、服务发现、断路器等),这些在 DDD 中被轻描淡写。DDD 假设了较强的团队自治能力,而微服务实践中的运维复杂度远超 DDD 的讨论范围。
- 为什么接着读:如果 DDD 让你理解了"为什么要拆"和"怎么拆",Richardson 让你理解"拆了之后怎么管"——分布式事务、API 网关、事件驱动架构等是 DDD 微服务化的必要补充。
知识网络位置
- 上游(先读):Martin Fowler《企业应用架构模式》—— 提供基础战术模式,建立对应用架构的基本认知。
- 本位:Eric Evans《领域驱动设计》—— 战略 + 战术设计的思想体系。
- 下游(再读):Vaughn Vernon《实现领域驱动设计》→ Chris Richardson《微服务架构设计模式》—— 从实操到分布式落地。
CH.08✨ 深度洞察摘录
统一语言是纪律而非文档
- 来源:《领域驱动设计》统一语言章节
- 类型:认知颠覆
- 核心内容:统一语言最常见的失败方式是"写一份术语表然后没人看"。Evans 的真正主张是:统一语言是一种持续的行为纪律——当代码中的命名与业务术语不一致时,这本身就是设计缺陷的信号,需要立即修复。语言的维护不是文档工作,而是代码质量工作。
- 可迁移到:任何需要跨专业协作的团队——产品团队的 PRD 术语统一、医疗团队的临床术语标准化、法律团队的合同用语规范。
限界上下文的本质是接受不一致
- 来源:《领域驱动设计》限界上下文章节
- 类型:可迁移模型
- 核心内容:大多数管理者的第一反应是"统一所有人的理解",但限界上下文的核心洞察是:在大型组织中,不同部门对同一个概念有不同理解是正常的、健康的、甚至必要的。问题不在于消除差异,而在于识别差异的边界并管理集成。这不是沟通失败,而是复杂系统的本质特征。
- 可迁移到:大型组织的架构设计、企业并购中的系统整合、多部门协作流程设计。
模型永远是现实的简化而非副本
- 来源:《领域驱动设计》全书核心思想
- 类型:金句级表达
- 核心内容:领域模型不是业务现实的精确副本,而是一种有意的简化和引导。好的模型会主动选择忽略某些现实细节,以突出最重要的结构。模型的价值不在于"完全正确",而在于"足够有用"——它是否帮助团队做出更好的设计决策,比它是否"真实"更重要。
- 可迁移到:数据建模、产品设计中的用户画像、战略规划中的市场分析。
康威定律是 DDD 的隐含基础
- 来源:《领域驱动设计》限界上下文与团队关系章节
- 类型:跨书共振
- 核心内容:DDD 的限界上下文与团队边界的对应关系,本质上是康威定律(组织结构决定系统架构)的应用。但 Evans 走得更远——他暗示可以反向利用康威定律:通过主动调整组织结构来引导系统架构的演化。你想让系统长成什么样,就先把团队组织成什么样。
- 可迁移到:组织架构设计、团队拆分决策、DevOps 团队建设。
贫血模型是 DDD 要消灭的头号敌人
- 来源:《领域驱动设计》领域模型章节
- 类型:认知颠覆
- 核心内容:贫血模型(对象只有数据字段,逻辑在 Service 层)是大多数企业系统的默认写法,也是 DDD 视角下的反模式。它的危害不是"技术上不对",而是"业务知识无法在代码中积累"——当所有业务规则都散落在 Service 方法中时,没有人能看到业务的全貌,改一处可能漏掉三处。充血的领域模型让业务知识有了"家"。
- 可迁移到:代码审查标准、新项目的技术选型决策、遗留系统的重构方向判断。