如何通过学习DDD构建强大的领域驱动设计软件架构?

摘要:DDD 是一套​**软件设计方法论**​,是一套思维方式,内心先有思路,再去学习我认为会好很多,所以先学习 DDD。
Eric Evans 的《领域驱动设计》,不是一种具体架构模式,而是一套思维方式,告诉你怎么划分边界、怎么建模。它可以和上面任何架构模式结合使用 背景 在最近的项目开发中,我的项目体量来到了一个更大的层面,且业务需求改动频率也变高了。我也首次被自己写的“屎山”代码绊住脚,修改一个需求,新加一个东西,发现只能用全局变量硬塞。 所以借这个机会深度了解了一下软件架构,以此作记录。 介绍 原文 译文 DDD 是一套​软件设计方法论​,是一套思维方式,内心先有思路,再去学习我认为会好很多,所以先学习 DDD。 核心思想 ​软件的设计应该由业务领域(Domain)来驱动​,用业务概念来组织代码,而不是用技术概念。 方法论 战略设计(Strategic Design) 战略设计解决架构问题,决定系统怎么拆,更重要。 通用语言(Ubiquitous Language) 定义: 追求开发和业务用同一套术语,代码里的命名直接反映业务语言 Note 你有没有遇到过这种情况 — 业务说"把这个款下架",开发理解成把数据库记录删了,但业务的意思是把商品状态改成不可见。问题出在"下架"这个词,双方理解不一样。 通用语言要求团队先对齐术语。比如大家约定: "下架" = 商品状态改为 inactive,不删除数据 "删除" = 物理删除记录 就比如说 sku,在电商项目里,sku ID 必须约定好,平台生成的 sku 叫平台 SKU,我们设定的 sku 要叫,在代码里的体现就是前者是 platform_sku 后者是 sku。 方法名、类名、模块名、甚至团队开会时嘴里说的词,都应该和代码里一致。它是一整套语言体系,不只是命名规范。 限界上下文(Bounded Context) 定义: 在这个边界里,所有术语和模型都有唯一含义,不同上下文里的同一个名字可以是完全不同的模型。 !!!这是 DDD 战略设计里最核心的概念。 Note 继续用电商业务。"商品"这个词在不同业务场景里含义完全不同: 商品管理 — 商品有标题、描述、图片、分类、上下架状态。运营关心的是怎么编辑、怎么展示。 订单履约 — 商品变成了"订单里的一行",关心的是 SKU、数量、单价、是否发货。标题描述无所谓。 库存管理 — 商品变成了"库存单位",关心的是在库数量、仓库位置、补货阈值。价格无所谓。 财务结算 — 商品变成了"收入项",关心的是成本、售价、利润率、税率。图片无所谓。 可能商品还是商品,本来就有很多很多字段, 不同业务场景里的“商品”本质上就是不同的业务概念,只不过碰巧都叫这个名字。 Bounded Context 的做法就是,让每个业务场景有自己的 Product,有多个 Product 类,只包含自己需要的类。 所以在限界上下文思维的指导下,自然整个项目会先按照业务场景分文件夹,每个业务场景有自己所需的数据(哪怕这些数据都可以归为 Product 类),但是每个业务场景会自己定义一个只包含自己所需的类。 在实践过程中,通过 Application 的调用来分配传入每个类自己所需的东西。 上下文映射(Context Map) Context Map 本身不是代码,它是一张架构图,画在白板或文档里,帮你理清上下文之间的关系。真正落到代码里的是各种集成方式,其中最常用的就是防腐层。理想状态每个项目可以先花心思做设计,设计图就是这玩意。 描述不同限界上下文之间的联系和通讯的。 上游/下游(Upstream/Downstream) 数据提供方是上游 消费方是下游 例如,Excel 模板分析、Excel 填写是一对上下游 防腐层(Anti-Corruption Layer, ACL) 对接外部系统的中间层,将外部信息格式对应到内部系统,让信息格式解耦。 可以单独放个 acl 目录,里面都是做防腐的。 ACL 的职责就是把外部数据结构转成自己上下文的领域模型,比如把 Temu API 返回的 JSON 转成自己定义的 Order 对象 共享内核(Shared Kernel) 两个上下文共用一小部分模型,尽量少用 子域(Subdomain) 把整个业务领域拆成核心域、支撑域、通用域,决定资源投入的优先级 避免过度设计带来的开销,先做优先级,判断资源倾斜。 核心域(Core Domain) 例如我们的印花生成、Excel 生成,值得精心设计做更好的架构,且需要经常维护更新。 支撑域(Supporting Subdomain) 能用就行。 通用域(Generic Subdomain) 用谁的都行,目的是有这个。 第三方,比如说什么支付功能。
阅读全文