Skip to content

限界上下文 = 系统的边界划分 ​

解决什么问题:如何把一个复杂的业务领域,划分为多个独立演化的子系统—— 让每个子系统有自己的模型,自己的语言,自己的演化节奏。

业务问题 ​

真实场景 ​

场景 1:电商系统的"订单"歧义

订单服务团队说"订单" = {订单号, 商品列表, 价格, 支付状态}
物流团队说"订单" = {运单号, 收货地址, 派送状态}
财务团队说"订单" = {账单号, 金额, 收款状态}

→ 三个团队用同一个词,含义完全不同
→ 一个"订单"改动要协调三个团队

场景 2:单体应用膨胀

业务跑通 1 年后:
- 单体代码库 50 万行
- 一个团队 20 人
- 部署频率 = 1 次/周(每次都有冲突)
- 一个 bug 影响所有业务

场景 3:跨团队集成混乱

A 团队:Bounded Context 内部用"用户" = {ID, 邮箱, 状态}
B 团队:通过 HTTP API 调用 A,需要"用户" = {ID, 邮箱, 状态, 偏好, 历史订单}

→ A 团队每次内部重构都破坏 B
→ B 团队要跟着 A 改
→ 互相拖累

失败的典型做法 ​

做法 1:按技术层划分

✗ 把"订单服务"拆为:
  - 订单 API 服务
  - 订单业务逻辑服务
  - 订单数据库服务

后果:业务完整性破坏,一个业务变更要协调三个服务

做法 2:按团队规模均分

✗ 每个团队负责一个 BC,不管业务是否相关

后果:业务相关性被切断,跨 BC 调用爆炸

做法 3:过早拆分

✗ 业务还没跑通就拆 5 个 BC

后果:复杂度 > 业务复杂度,协调成本 > 业务价值

控制论视角 ​

数学原型 ​

钱学森《工程控制论》Ch 6 §6.3: "设法确定控制矩阵的元素 Ckν(s) 与 C′kμ(s) 须要满足什么条件, 才能使规定的控制信号 Xj(s) 与 Ξμ(s) 只影响和它们相应的受控量 Yj(s) 和 Wμ(s), 而不影响其余的受控量。"

钱学森 §6.3: "这里的数学问题也就是如何把图 6.2-4 中的系统矩阵加以对角线化的问题。"

控制论解法 ​

多变量控制系统:

[ Y1 ]     [ E11 E12 ... E1n ] [ W1 ]
[ Y2 ]  =  [ E21 E22 ... E2n ] [ W2 ]
[ .. ]     [ ... ... ... ... ] [ .. ]
[ Yi ]     [ Ei1 Ei2 ... Ein ] [ Wn ]

限界上下文 = 对角线化:
- 让每个 Wi 只影响 Yi
- 非对角元素 = 0(无跨上下文影响)

[ Y1 ]     [ E11  0  ...  0  ] [ W1 ]
[ Y2 ]  =  [  0  E22 ...  0  ] [ W2 ]
[ .. ]     [ ... ... ... ... ] [ .. ]
[ Yi ]     [  0   0  ... Ein ] [ Wn ]

与业务的对应 ​

控制论概念软件工程
互不影响子系统Bounded Context
矩阵对角化BC 边界划分
控制矩阵元素跨 BC 调用关系
受控量BC 内部状态
控制量BC 对外暴露的接口

核心概念 ​

定义 ​

限界上下文(Bounded Context):一个模型在其中成立的边界。同一个词在不同 BC 里可以有不同的含义;每个 BC 有自己的通用语言、自己独立演化的能力。

关键属性 ​

属性含义软件工程对位
边界明确模型只在 BC 内部成立服务边界、模块边界
通用语言BC 内部用一致的术语Ubiquitous Language
独立演化BC 改动不影响其他 BC服务独立部署
数据所有权BC 拥有自己的数据数据库隔离
团队对齐一个 BC 对应一个小团队团队拓扑

边界划分的三层标准 ​

┌────────────────────────────────────────┐
│ 业务完整性(最重要)                       │
│ - 这个 BC 能独立提供完整的业务价值吗?      │
└────────────────────────────────────────┘
                │
                ↓
┌────────────────────────────────────────┐
│ 团队规模(次要)                          │
│ - 一个 BC 对应一个 ≤ 10 人的小团队         │
└────────────────────────────────────────┘
                │
                ↓
┌────────────────────────────────────────┐
│ 技术可行性(最后考虑)                     │
│ - 这个 BC 能否独立部署?独立扩缩?         │
└────────────────────────────────────────┘

工程实践 ​

步骤 1:用 Event Storming 识别领域事件 ​

输入:业务专家 + 技术人员一起工作坊

输出:
- 所有领域事件列表("订单已创建""支付已完成"等)
- 每个事件的发布者(聚合根)
- 每个事件的订阅者

工具:
- 便利贴(黄色 = 领域事件)
- 时间线(从左到右)

步骤 2:识别聚合根与一致性边界 ​

步骤:
1. 把领域事件按"必须同时发生"分组
2. 每个分组 = 一个聚合
3. 聚合的入口 = 聚合根

判断标准:
- 同一聚合内的对象,必须作为一个整体修改
- 不同聚合的对象,可以独立修改

例:
- 订单 + 订单项 = 一个聚合(订单是聚合根)
- 订单 + 用户 = 不同聚合(通过用户ID引用,不修改用户)

步骤 3:识别 BC 边界 ​

三种 BC 边界识别法:

1. **业务不变性识别法**
   - 找出"不会随时间变化的核心业务规则"
   - 每组不变性 = 一个 BC

2. **业务能力识别法**
   - 业务能力(如"下订单""发货""收款")= BC
   - 每个业务能力独立演化

3. **组织结构识别法**
   - 团队边界 = BC 边界(康威定律)
   - 适合组织已经定型的场景

步骤 4:验证拆分粒度 ​

┌──────────────┬────────────────────────────┐
│  评估维度     │  健康标准                    │
├──────────────┼────────────────────────────┤
│  内聚度       │  BC 内方法调用密度 > 80%      │
│  耦合度       │  跨 BC 调用次数 / BC 内 < 0.2 │
│  协调成本     │  协调成本 < 业务总成本 20%    │
│  变更独立性   │  一年内跨 BC 协调 < 20%       │
│  故障隔离     │  一 BC 故障不影响其他 BC       │
└──────────────┴────────────────────────────┘

步骤 5:建立 Context Map ​

Context Map(上下文映射图):

[订单 BC] ──Customer-Supplier──> [支付 BC]
    │                              │
    └──Shared Kernel──[用户模型]──┘
                                  │
                [物流 BC]──ACL──┘

每个 BC 之间的关系都要明确标注:
- Customer-Supplier(上下游)
- Shared Kernel(共享内核)
- Anti-Corruption Layer(防腐层)
- Conformist(跟随)
- Separate Ways(独立)

常见反模式 ​

反模式 1:技术驱动拆分 ​

症状:按技术层(前端/后端/数据库)拆分
后果:业务完整性破坏
正解:业务驱动拆分

反模式 2:拆分过细 ​

症状:5 个服务做一个小业务
后果:协调成本 > 业务价值
正解:等到痛点出现再拆分

反模式 3:拆分过粗 ​

症状:单体 100 万行,所有业务挤在一起
后果:部署冲突、性能干扰、升级困难
正解:识别不变性,按业务能力拆分

反模式 4:忽略组织对齐 ​

症状:BC 边界与团队边界不一致
后果:康威定律反噬,跨团队协调爆炸
正解:BC 边界 ⊆ 团队边界

工程实例:电商系统的 BC 划分 ​

[用户 BC]
  ├─ 模型:用户 {ID, 邮箱, 偏好, 状态}
  ├─ 接口:注册、登录、修改偏好
  └─ 团队:用户团队

[商品 BC]
  ├─ 模型:商品 {SKU, 名称, 价格, 库存}
  ├─ 接口:查询商品、调整库存
  └─ 团队:商品团队

[订单 BC]  ← 用户通过 ACL 调用
  ├─ 模型:订单 {订单号, 商品列表, 金额, 状态}
  ├─ 接口:创建订单、取消订单
  └─ 团队:订单团队

[支付 BC]  ← Customer-Supplier
  ├─ 模型:支付 {支付ID, 金额, 状态, 流水}
  ├─ 接口:发起支付、查询支付状态
  └─ 团队:支付团队

[物流 BC]  ← Customer-Supplier
  ├─ 模型:运单 {运单号, 收货地址, 状态}
  ├─ 接口:创建运单、更新状态
  └─ 团队:物流团队

性能指标 ​

拆分质量指标 ​

指标设计目标实际值衡量方法
内聚度BC 内调用 > 80%待测Jaeger 调用链分析
耦合度跨 BC 调用 / BC 内 < 0.2待测服务网格统计
协调成本协调成本 < 业务总成本 20%待测工时统计
变更独立性一年内跨 BC 协调 < 20%待测PR / Git 数据分析
故障隔离一 BC 故障不影响其他 BC待测混沌工程

业务健康指标 ​

指标设计目标实际值衡量方法
新功能交付周期< 2 周待测研发效能
故障爆炸半径≤ 1 BC待测故障演练
部署频率每 BC 独立可部署待测CI/CD 数据
跨 BC 协调 PR 数< 20%待测GitHub 数据

监控设计 ​

关键监控:
- BC 内调用次数(业务正常 = 高)
- 跨 BC 调用次数(业务耦合 = 低,但应监控)
- 跨 BC 调用延迟(业务集成健康)
- BC 故障率(隔离是否生效)
- 协调成本工时(团队健康)

边界判断 ​

何时不用 ​

场景 1:单进程应用

- 业务量小(< 10 万用户)
- 团队规模小(< 5 人)
- 没有分布式假设
→ 不需要 BC,单体足够

场景 2:业务完全跑通前

- 业务模式还没稳定
- 频繁改动的早期阶段
→ 不要过早 BC 划分,先跑通业务

场景 3:业务量小但分布广

- 100 个 BC,每个 BC 用户数 < 100
→ 协调成本 > 业务价值
→ 应该合并 BC

与其他方法论的边界 ​

相邻概念区别
微服务微服务是技术实现;BC 是业务边界(一个 BC 可以是 1 个或多个微服务)
模块模块是代码组织;BC 是业务自治单元
子域子域是问题空间的划分;BC 是解决方案空间的划分
聚合聚合是数据一致性边界;BC 是业务自治边界

何时升级(更复杂的方法论) ​

当以下情况出现时,考虑更复杂的协调机制:

1. 跨 BC 协调 > 50% → 重新划分 BC
2. 一个 BC 超过 20 人 → 拆分 BC
3. BC 间一致性要求强 → 引入 Saga / 分布式事务
4. 业务规模暴涨 → 考虑 CQRS / Event Sourcing

关键洞察 ​

限界上下文不是技术决策,而是业务决策。

划分错误 = 业务协作成本爆炸。

划分的核心是"业务不变性"——识别哪些业务规则是稳定的,按不变性划分 BC。

相关链接 ​

IDDD 对位 ​

  • BC = 战略边界 → 子域分类(Ch 2):一个子域至少一个 BC
  • BC 间关系 → 9 种 BC 关系(Ch 3 ★★★★★):Partnership / Shared Kernel / Customer-Supplier / Published Language 等
  • Module vs BC → Module vs Bounded Context(Ch 9):Module 是开发单元,BC 是业务边界
  • 集成 → 集成成熟度模型(Ch 13):ACL 保护 BC 完整性

核心:BC 是 DDD 的"战略武器"——控制论 Ch 21"分散系统协调"在业务语言的形式化。

从名家方法论与工程化思路中蒸馏出自己的工程体系。