Home

常见大型软件架构设计快速入门101

DDD

常见大型软件架构设计快速入门101

常见大型软件架构设计快速入门 101(面向入门到上手) 大型软件架构的目标不是“炫技”,而是在复杂需求、多人协作、长期演进下,依然能做到:可扩展、可维护、可用、可观测、可交付。本文用“101”方式,把常见架构形态、核心原则、关键组件与落地步骤串起来,帮助你快速建立整体框架。 --- 大型系统与小系统的关键差异 小系统通常关注“功能实现”;大型系统更关注“变化与风险”。 变化:需求、流量、团队、技术

DDD 是什么:把“业务复杂度”放回软件设计中心

DDD(Domain-Driven Design,领域驱动设计)不是某种框架或微服务模板,而是一套在复杂业务下更容易保持“可理解、可演进”的建模与架构方法。它的核心思想是:

软件的结构应当围绕“领域(业务)”来组织,而不是围绕技术层(Controller/Service/DAO)或数据库表来组织。

在你提供的文章语境里,DDD 被放在“可维护性”“清晰边界与稳定契约”“为未来拆分铺路”这些目标之下,因此它更像一种划分模块边界、控制复杂度、降低协作摩擦的手段。


DDD 解决的典型痛点

在大型系统里,最难的是“长期变化”。DDD 常用来对抗这些问题:

  • 业务语言不统一:产品说“订单关闭”,研发说“状态=9”,测试说“取消”,最后代码里出现三套概念。
  • 模型失真:代码结构跟业务不一致,新增功能只能“到处 if/else”。
  • 边界模糊:一个需求要改 10 个模块,且彼此互相直接引用数据库或内部类。
  • 一致性失控:为了一个功能跨表跨服务强事务,导致性能和可用性风险。

两大支柱:战略设计 vs 战术设计

1) 战略设计(Strategic Design):先把边界划清楚

战略设计关心“系统怎么拆、团队怎么协作、模型在哪些边界内成立”。

  • 限界上下文(Bounded Context)
    同一个词在不同上下文含义可能不同,DDD 允许它们并存,但要求边界内自洽、边界间通过契约连接。
    例:

    • 在“交易上下文”里,Order 关注支付、履约状态
    • 在“客服上下文”里,Order 关注投诉、补偿、工单关联
      两边都叫 Order,但字段、规则、生命周期可能完全不同。
  • 上下文映射(Context Mapping):上下文之间怎么集成
    常见方式包括:API 调用、事件订阅、共享内核(谨慎)、防腐层(ACL)等。
    其中 防腐层(Anti-Corruption Layer) 很关键:用一层适配把外部系统的“脏模型”隔离开,避免污染自己的领域模型。

2) 战术设计(Tactical Design):在边界内把模型做好

战术设计关心“代码怎么写更贴近业务模型”。

  • 实体(Entity):有身份(id),生命周期中属性会变
  • 值对象(Value Object):无身份、不可变,靠值相等(例如 Money、Address)
  • 聚合(Aggregate)与聚合根(Aggregate Root):一致性边界
    聚合根是唯一对外入口,外部不能随意改聚合内部对象。
  • 领域服务(Domain Service):不适合放在某个实体里的业务规则
  • 领域事件(Domain Event):领域里发生了“重要事实”,用于解耦和异步扩展
  • 仓储(Repository):以“聚合”为单位的持久化抽象(不是表级 CRUD)

聚合:文章里提到的“事务一致性边界”如何理解?

聚合的本质:你愿意为哪些对象付出“强一致(同一事务)”的成本。
DDD 建议:尽量小聚合,否则并发、性能、锁竞争都会变差。

举个电商例子:

  • Order(订单)作为聚合根
  • OrderItem(订单项)属于 Order 聚合内部

那么外部修改订单项通常要通过聚合根方法:

java
class Order {  private OrderId id;  private List<OrderItem> items;  private OrderStatus status;
  public void changeItemQuantity(SkuId skuId, int qty) {    if (status != OrderStatus.DRAFT) throw new IllegalStateException("不可修改");    // 在聚合内维护不变量:数量>0、库存校验策略等  }}

不要让别的模块直接拿到 OrderItemRepository 去改某一行记录,因为这会绕过聚合不变量与一致性规则。


DDD 与“模块化单体 / 微服务”的关系

DDD 不是“必须微服务”,反而常见正确路径是:

  • 先用 DDD 把单体做成模块化单体
    • 每个限界上下文 = 一个清晰模块
    • 模块之间只通过接口/事件交互
  • 当组织和交付节奏需要时,再把某些上下文拆成独立服务
    这时你会发现:边界、数据归属、契约早已更清晰,拆分成本更低。

一个简化的 DDD 分层视图(帮助落地)

DDD 常与“整洁架构/六边形架构”结合,形成清晰依赖方向:

  • 应用层:编排用例(事务、调用领域对象、发布事件),不写复杂规则
  • 领域层:业务规则与不变量核心
  • 基础设施层:技术细节(ORM、MQ 客户端、第三方 SDK)

你可以继续深入的子主题(建议钻研顺序)

  • 限界上下文识别方法:事件风暴(Event Storming)、业务能力地图
  • 聚合设计原则:不变量、并发、最终一致性与 Saga
  • 领域事件与 EDA 的结合:Outbox、幂等、事件版本兼容
  • 防腐层(ACL)实践:如何隔离外部支付/ERP 的模型污染
  • Repository 的边界:以“聚合”为单位 vs 以“查询”为单位(与 CQRS 配合)

如果你告诉我你的业务场景(例如订单/支付/库存/内容),我可以用 DDD 的方式帮你画出可能的限界上下文与聚合边界,并指出哪些地方适合用事件解耦、哪些地方必须强一致。

DDD — 常见大型软件架构设计快速入门101 - Drill