3. 限界上下文(Bounded Context)识别:通过业务事件风暴(Event Storming)识别核心域、支撑域、通用域
在领域驱动设计中,限界上下文(Bounded Context)是划分系统边界的基本单元。它定义了模型在特定上下文中含义的边界,确保术语、规则和业务逻辑在该边界内保持一致性。本节将介绍如何通过业务事件风暴(Event Storming)这一协作建模技术,系统性地识别出核心域、支撑域和通用域,并最终确定微服务的拆分边界。
3.1 业务事件风暴概述
事件风暴是由 Alberto Brandolini 提出的一种工作坊式建模方法,通过跨职能团队(业务专家、产品经理、开发人员、测试人员)的协作,在短时间内快速梳理出完整的业务全景。其核心产出物包括:
- 领域事件(Domain Event):业务中发生的、对业务有重要意义的事实(如“订单已提交”、“库存已扣减”)。
- 命令(Command):触发领域事件的操作(如“提交订单”、“扣减库存”)。
- 聚合(Aggregate):一组具有内聚性的实体和值对象,是事务一致性的边界。
- 外部系统(External System):与当前系统交互的第三方服务或遗留系统。
- 用户(User/Actor):发起命令的角色。
实践建议:事件风暴工作坊建议控制在 8-12 人,使用不同颜色的便利贴(如橙色=领域事件、蓝色=命令、粉色=外部系统、绿色=用户),在长条白纸上按时间轴从左到右排列。整个过程通常需要 2-4 小时。
3.2 从领域事件到限界上下文
事件风暴完成后,团队会得到一张覆盖完整业务流的事件全景图。接下来,需要根据以下原则对领域事件进行分组,识别出限界上下文:
- 语言一致性:同一组内使用的业务术语含义必须唯一,不存在歧义。
- 事务边界:需要保持强一致性(ACID)的聚合应属于同一个限界上下文。
- 变化频率:变化速率和原因相似的业务逻辑倾向于放在同一个上下文中。
- 团队结构:遵循康威定律,限界上下文通常对应一个独立团队负责的微服务。
以下表格展示了在电商场景中,通过事件风暴识别出的典型限界上下文及其对应的领域事件示例:
| 限界上下文 | 典型领域事件 | 核心业务术语 |
|---|---|---|
| 订单上下文 | 订单已创建、订单已支付、订单已取消 | 订单、订单项、收货地址 |
| 库存上下文 | 库存已扣减、库存已释放、库存不足 | SKU、库存量、仓库 |
| 支付上下文 | 支付已发起、支付已成功、支付已退款 | 交易流水、支付渠道、对账单 |
| 物流上下文 | 包裹已发货、包裹已签收、配送异常 | 运单、物流商、配送站 |
| 用户上下文 | 用户已注册、用户已认证、用户等级变更 | 账户、会员等级、积分 |
3.3 核心域、支撑域与通用域的划分
识别出限界上下文后,需要进一步将其归类为三种域类型,以指导资源投入和架构决策:
- 核心域(Core Domain):企业最核心的竞争力所在,是业务差异化的来源。需要投入最多的资源进行自研和持续优化。
- 支撑域(Supporting Subdomain):支撑核心业务运转,但本身不构成核心竞争力。通常需要定制开发,但复杂度低于核心域。
- 通用域(Generic Subdomain):行业通用能力,有成熟的开源或商业解决方案。优先考虑采购或使用现成产品,避免重复造轮子。
判断标准:问业务专家一个问题——“如果这个系统出问题了,公司会损失多少钱?如果换成竞争对手的系统,用户能感知到区别吗?” 如果损失巨大且用户能明显感知,则属于核心域;如果损失可控且用户无感知,则可能是通用域。
以下 SVG 图展示了通过事件风暴识别出的限界上下文及其域类型归属:
3.4 实战案例:电商平台域划分
以一个典型的 B2C 电商平台为例,通过事件风暴识别出的限界上下文及其域类型划分如下:
| 限界上下文 | 域类型 | 划分理由 | 推荐策略 |
|---|---|---|---|
| 订单上下文 | 核心域 | 订单流程是电商的核心体验,涉及复杂的业务规则(拆单、合并、退款) | 自研,持续投入 |
| 促销上下文 | 核心域 | 促销策略(满减、秒杀、优惠券)是平台吸引用户的关键差异化能力 | 自研,高优先级 |
| 库存上下文 | 支撑域 | 需要与订单紧密配合,但逻辑相对标准化,存在行业最佳实践 | 自研,复用模式 |
| 支付上下文 | 通用域 | 对接支付宝、等成熟支付渠道,核心逻辑由第三方提供 | 集成 SDK,轻量封装 |
| 用户上下文 | 通用域 | 注册、登录、密码管理等功能有成熟的开源方案(如 Keycloak) | 采购或开源方案 |
常见误区:不要将所有与“用户”相关的功能都归入通用域。如果用户等级体系、会员权益是平台的核心竞争力(如京东 Plus、淘宝 88VIP),则这部分应划入核心域。通用域只包含那些“换一家供应商用户完全无感知”的能力。
3.5 限界上下文与微服务边界
识别出限界上下文后,每个限界上下文通常对应一个独立的微服务。但需要注意以下映射规则:
- 一对一映射:一个限界上下文对应一个微服务,这是最理想的情况。
- 一对多映射:当限界上下文内部存在明显的性能差异或部署频率差异时,可以拆分为多个微服务(如将“订单查询”与“订单写入”分离)。
- 多对一映射:对于非常简单的支撑域或通用域,可以将多个限界上下文合并为一个微服务(如将“通知”和“短信”合并)。
以下 SVG 图展示了限界上下文与微服务之间的映射关系:
3.6 识别过程中的常见陷阱
陷阱一:过度拆分
将“订单创建”和“订单查询”拆成两个微服务,但两者共享同一个数据库,导致分布式事务和跨服务查询的复杂度剧增。正确做法:先保持一个限界上下文,当确实存在性能瓶颈时再考虑拆分。
将“订单创建”和“订单查询”拆成两个微服务,但两者共享同一个数据库,导致分布式事务和跨服务查询的复杂度剧增。正确做法:先保持一个限界上下文,当确实存在性能瓶颈时再考虑拆分。
陷阱二:忽略上下文映射
识别出限界上下文后,没有定义上下文之间的映射关系(如合作关系、防腐层、开放主机服务),导致服务间耦合严重。每个限界上下文必须明确其与外部上下文的集成方式。
识别出限界上下文后,没有定义上下文之间的映射关系(如合作关系、防腐层、开放主机服务),导致服务间耦合严重。每个限界上下文必须明确其与外部上下文的集成方式。
陷阱三:术语污染
在“订单上下文”中使用“用户”表示买家,在“物流上下文”中使用“用户”表示收货人,导致模型混乱。必须为每个上下文中的同名术语建立明确的上下文映射表。
在“订单上下文”中使用“用户”表示买家,在“物流上下文”中使用“用户”表示收货人,导致模型混乱。必须为每个上下文中的同名术语建立明确的上下文映射表。
3.7 小结
通过事件风暴识别限界上下文是 DDD 建模的核心环节。关键产出包括:
- 一张完整的领域事件全景图,覆盖所有核心业务流程。
- 一组清晰的限界上下文,每个上下文拥有统一的语言和事务边界。
- 明确的域类型划分(核心域、支撑域、通用域),指导资源投入和架构决策。
- 初步的微服务边界建议,为后续的模块拆分和接口设计奠定基础。