读书笔记 · 约 10,918 字 · 预计推送 2 部分

《领域驱动设计》选读:战略设计、限界上下文与通用语言 —— 对个人项目与单体服务仍有效的部分 未开始

目录

题记与说明


一、精读来源清单(5 个,均已通读)

#来源角色链接
1Eric Evans, *Domain-Driven Design Reference* (2015-03, 官方模式与定义摘要, CC BY 4.0),8 页 PDF 已下载并全文转文本精读原典级:书中全部模式定义的逐字压缩版页面 / PDF 直链
2Martin Fowler, "Bounded Context" (bliki, 2014-01-15)权威二手:解读 Evans 原书结论与适用条件https://martinfowler.com/bliki/BoundedContext.html
3Petter Holmström, "DDD Part 1: Strategic Domain-Driven Design" (Vaadin blog, 2023)现代结构化讲解:子域三分类、问题/方案空间、小团队警告https://vaadin.com/blog/ddd-part-1-strategic-domain-driven-design
4Robert Laszczak (Three Dots Labs), "Microservices or monolith? It's detail"单体内的限界上下文实操:Clean Monolith、通信规则、CI 强制工具 go-cleanarchhttps://threedots.tech/post/microservices-or-monolith-its-detail/
5Jon P Smith, "My experience of using modular monolith and DDD architectures" (2021)单人项目第一手经验报告:22 个项目的模块化单体 + DDD,时间压力下的真实得失https://www.thereformedprogrammer.net/my-experience-of-using-modular-monolith-and-ddd-architectures/

辅助检索:WebSearch("DDD bounded context monolith small project overkill modular monolith")确认了社区共识:限界上下文作为思维工具几乎处处适用;全套战术机器与微服务拆分只在多团队/复杂域/有拆分计划时才划算(代表性观点见 Milan Jovanović 与 kgrzybek/modular-monolith-with-ddd)。


二、原典逐字定义与关键引述(来源 #1,DDD Reference PDF,p.2–41)

以下引文为 PDF 转文本的逐字摘录(去除了原 PDF 的连字符排版差异)。该文档为 CC BY 4.0 许可,允许署名转载。

Bounded Context(p.2)——问题陈述:

"Multiple models are in play on any large project. … Multiple models are inevitable, yet when code based on distinct models is combined, software becomes buggy, unreliable, and difficult to understand."
"Model expressions, like any other phrase, only have meaning in context."

Therefore(模式的核心处方):

"Explicitly define the context within which a model applies. Explicitly set boundaries in terms of team organization, usage within specific parts of the application, and physical manifestations such as code bases and database schemas. Apply Continuous Integration to keep model concepts and terms strictly consistent within these bounds, but don't be distracted or confused by issues outside."

Ubiquitous Language(p.3–4):

"Translation blunts communication and makes knowledge crunching anemic."
"Use the model as the backbone of a language. Commit the team to exercising that language relentlessly in all communication within the team and in the code. Within a bounded context, use the same language in diagrams, writing, and especially speech."
"Recognize that a change in the language is a change to the model."

Continuous Integration(p.5)——注意它不是指 CI/CD 工具,而是指模型/代码的持续合并:

"When a number of people are working in the same bounded context, there is a strong tendency for the model to fragment. The bigger the team, the bigger the problem, but as few as three or four people can encounter serious problems."

Context Map(p.28–29):

"Identify each model in play on the project and define its bounded context. … Name each bounded context, and make the names part of the ubiquitous language. Describe the points of contact between the models, outlining explicit translation for any communication… Map the existing terrain. Take up transformations later."

七种上下文关系模式(p.31–37),各自 Therefore 的要点逐字摘录:

Distillation(p.39–41):

Core Domain: "Make the core small. Apply top talent to the core domain… Justify investment in any other part by how it supports the distilled core."
Generic Subdomains: "Identify cohesive subdomains that are not the motivation for your project. … consider off-the-shelf solutions or published models for these generic subdomains."

Big Ball of Mud(p.38):

"Draw a boundary around the entire mess and designate it a big ball of mud. Do not try to apply sophisticated modeling within this context. Be alert to the tendency for such systems to sprawl into other contexts."

三、七维提取

1. 核心问题

软件最贵的复杂度往往不在技术而在领域本身。Evans 在战略设计部分回答三个问题:

  1. 模型放不下:大系统中多个模型必然并存(不同团队、不同用户群、不同工具链),强行合并成一个大一统模型行不通——Fowler 转述 Evans 的结论:"total unification of the domain model for a large system will not be feasible or cost-effective"。多义术语在口语里能糊弄过去,在计算机里不行(Fowler 的电力公司例子:meter 对不同部门分别指"电网到位置的连接""电网到用户的连接""可更换的物理电表")。
  2. 语言分裂:领域专家、开发者、代码各自一套词汇,翻译消耗认知:"Translation blunts communication and makes knowledge crunching anemic."
  3. 精力错配:稀缺的高级开发者天然流向技术基建或"没有领域知识也能啃"的整洁问题,真正的业务资产(核心域)反而被 neglected。

2. 主要主张

  1. 模型只在上下文中有意义 → 显式定义边界(Bounded Context),边界体现在团队组织、应用的特定部分、代码库与数据库 schema 等物理形态上。
  2. 通用语言即模型:语言变了模型就变了,代码是语言的最终载体;同一上下文内,图、文字、口语、代码必须用同一套词。
  3. 上下文之间要画地图(Context Map):显式命名每个上下文、显式写出翻译点;先用现有地形,以后再改造。
  4. 蒸馏:区分核心域/支撑子域/通用子域,"Make the core small",通用域考虑现成方案;其他一切投入都要"justify by how it supports the distilled core"。
  5. 集成是有价的决策,不是默认动作:七种关系模式给出了从"共享内核"到"彻底不集成"(Separate Ways)的谱系;烂系统也要画边界(Big Ball of Mud),只是别在里面做精细建模。

3. 方法

4. 数据与证据

证据类型是模式文献 + 从业者经验报告,不是受控实验,没有量化收益数据。具体支撑:

是否充分:对"概念有效、可落地"是充分的;对"收益多大、何时过度"只有定性经验,不充分——这部分靠多个独立来源收敛一致来补强。

5. 结论

战略设计的思想内核 20 年后依然成立,且对个人项目/单体尤其有效的是它的"边界思维",而不是它的"服务拆分"表象:

  1. 通用语言照常适用——单人项目里语言分裂发生在"现在写代码的我"与"三个月后读代码的我"之间;术语表 + 命名一致性是最低成本的防碎片手段。
  2. 单体内部照样可以(也往往应该)有多个限界上下文:"whether the application is a microservice or a monolith is an implementation detail"(#4)。模块间只走接口 + DTO(transport types),不 import 对方 domain 层;单体免费赠送编译期契约检查,微服务反而要靠人工维护 API 契约。
  3. 数据重复 ≠ 行为重复(#4):跨上下文复制一份订单快照字段不是坏味道,翻译/映射才是保持模型独立所需。
  4. 蒸馏对个人项目是放大器:单人时间最稀缺,"核心域优先 + 通用域买现成"直接就是排期原则;"不想清楚要不要集成"时默认 Separate Ways。
  5. 拆分路径是先单体后服务:#4 引 Fowler:"Almost all the successful microservice stories have started with a monolith that got too big." 模块边界画得好,将来抽取服务只动接口层和基础设施层。

6. 局限

7. 对我的启发(个人项目与单体服务的落地清单)

直接照做:

  1. 每个项目维护一页术语表(glossary),代码命名、数据库字段、笔记/文档用同一套词;改词=改模型,改词要连代码一起改("Recognize that a change in the language is a change to the model")。单人项目审查者就是未来的自己,这条防的是"三个月后自己读不懂"。
  2. 单体按限界上下文分包/分模块;跨模块只调用对方暴露的接口并使用独立 DTO,禁止 import 对方 domain 层;能用编译器/lint/CI 规则强制的就不要靠自觉(go-cleanarch 思路,任何语言都可以抄这条规则)。
  3. 启动期只承认一个核心域 + 一个上下文;新上下文只在语言确实变了时才切出来("you need a different model when the language changes",Fowler)。
  4. 每次想加功能/加集成时先问:这是核心域吗?不是 → 现成方案(Generic Subdomains:"consider off-the-shelf solutions");集成收益小 → Separate Ways。
  5. 包第三方 API/LLM 服务时套一层 ACL:让上游的模型(字段名、报错结构、分页语义)死在翻译层里,不渗进自己的 domain。

降级使用:

明确不做:


四、来源链接汇总

  1. Eric Evans, *Domain-Driven Design Reference* (2015-03):<https://www.domainlanguage.com/ddd/reference/>(PDF:<https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf>,CC BY 4.0)
  2. Martin Fowler, "Bounded Context":<https://martinfowler.com/bliki/BoundedContext.html>
  3. Petter Holmström, "DDD Part 1: Strategic Domain-Driven Design":<https://vaadin.com/blog/ddd-part-1-strategic-domain-driven-design>
  4. Robert Laszczak, "Microservices or monolith? It's detail":<https://threedots.tech/post/microservices-or-monolith-its-detail/>
  5. Jon P Smith, "My experience of using modular monolith and DDD architectures":<https://www.thereformedprogrammer.net/my-experience-of-using-modular-monolith-and-ddd-architectures/>
  6. 辅助:Milan Jovanović, "Build a Modular Monolith in .NET":<https://milanjovanovic.tech/blog/build-modular-monolith-dotnet-step-by-step>;kgrzybek/modular-monolith-with-ddd:<https://github.com/kgrzybek/modular-monolith-with-ddd/discussions/213>
← 资料库今日播报 →