Shared Kernel(共享内核)
解决什么问题:多个 BC 共享一组核心概念(如 UserId / Money / TenantId)——重复定义会导致类型不兼容和翻译成本——Shared Kernel 让多个 BC 共享一部分代码/模型,但必须联合管理避免单方修改。
它是什么
Shared Kernel 是 Vernon 9 种 BC 关系之一——两个或多个 BC 共享一个共同的内核(代码库 / 模型):
- 共享内容:类型定义(UserId、Money)、基础值对象、枚举、常量
- 联合管理:任何一方修改必须通知其他方(共同决策)
- 同步发布:所有使用方同时升级到新版本
- 编译时共享:通常是同一代码库 / 同一 Maven 模块 / 同一 npm 包
Vernon Ch 3: "Two teams agree to share a subset of the domain model. They agree on the parts that they will share." "Explicitly designate which classes belong to the Shared Kernel and create a process for keeping that kernel small and free of contention."
V2 视角(V2 B3 分解的反向):Shared Kernel = 主动承认某些部分无法独立分解——把不可避免的耦合显式化、集中管理。
关键属性
| 属性 | 值/含义 |
|---|---|
| 共享内容 | 类型定义 + 基础值对象 + 常量(不包含业务逻辑) |
| 范围 | 2-3 个 BC(超过 3 = 拆分失败) |
| 管理方式 | 联合所有方共同决策 + 同步发布 |
| 变更流程 | 修改前必须通知所有使用方 → 决策 → 同步升级 |
| 版本控制 | SemVer 严格遵守(破坏性改动 = MAJOR bump) |
| 反模式 | 共享业务逻辑 / 共享 Repository / 共享数据库 |
| 核心约束 | 共享内核必须保持小——超过 10 个类 = 拆分失败 |
怎么用
场景 1:识别 Shared Kernel 候选
识别标准:
- 两个 BC 都使用相同的基础类型(UserId / TenantId / Money)
- 这些类型没有业务逻辑(只是标识符或值对象)
- 翻译成本高——每个 BC 自己定义 UserId,会导致类型不兼容
- 修改频率低——共享内核要稳定
典型共享内容:
- ID 类型(UserId / OrderId / TenantId)
- 通用值对象(Money / Address / TimeRange)
- 枚举(Status / Currency)
- 常量(错误码 / 业务规则编号)
场景 2:Shared Kernel 实现(独立包)
shared-kernel/
├── src/
│ ├── ids/
│ │ ├── UserId.ts
│ │ ├── OrderId.ts
│ │ └── TenantId.ts
│ ├── values/
│ │ ├── Money.ts
│ │ └── Address.ts
│ └── constants/
│ └── error-codes.ts
├── package.json (SemVer 严格管理)
└── CHANGELOG.md (破坏性改动明确标记)版本管理:
- v1.0.0 → v1.1.0 = 加方法(向后兼容)
- v1.1.0 → v2.0.0 = 破坏性改动(所有 BC 同步升级)
场景 3:修改流程(联合决策)
修改 Shared Kernel 的标准流程:
- 提出变更:任何一方提 PR 到 Shared Kernel 仓库
- 通知所有使用方:邮件 + Slack + 团队会议
- 评审:所有相关团队必须参与 PR 评审
- 决策:共识通过 → 合并;不通过 → 拒绝或延后
- 同步升级:发布新版本 → 所有 BC 同步升级 → 同步部署
- 回滚预案:如有 BC 无法升级,必须先协调后再发布
场景 4:Shared Kernel 与其他关系的区别
| 维度 | Shared Kernel | Customer-Supplier | Published Language |
|---|---|---|---|
| 耦合度 | 高(共同代码) | 中(API 调用) | 低(标准数据格式) |
| 变更成本 | 高(所有方同步) | 中(下游适配) | 低(按版本迁移) |
| 灵活性 | 低(受共同代码约束) | 中(上下游独立演化) | 高(PL 仅约束数据格式) |
| 适用 | 共享基础类型 | 上下游清晰 | 多客户跨组织 |
常见误区
- "Shared Kernel = 共享所有代码"——错。Shared Kernel 越小越好。共享业务逻辑 = 应该合并 BC
- "Shared Kernel 包含 Repository"——错。Repository 是聚合根的持久化抽象,是 BC 私有。共享 = 暴露 BC 内部细节
- "Shared Kernel 包含数据库表"——错。共享数据库 = 失去 BC 自治(V2 B3 分解的目标)
- "单方任意修改"——错。联合管理是核心。任意修改 = 其他 BC 无声破坏
- "Shared Kernel 越长越大"——错。超过 10 个类 = 拆分失败——应该合并 BC 或拆出独立工具库(Generic Subdomain)
- "Shared Kernel = Customer-Supplier"——错。Shared Kernel 是共同代码,C-S 是调用关系。前者编译时耦合,后者运行时耦合
关键洞察
Shared Kernel = "主动受控的耦合"——承认有些部分无法独立分解,把耦合显式化。
何时选 Shared Kernel:
- 共享基础类型(UserId 等)— 不可避免
- 共享类型稳定(修改频率低)
- 使用方有能力联合管理(团队协作良好)
何时不选 Shared Kernel:
- 共享业务逻辑 → 合并 BC
- 共享 Repository / 数据库 → 拆分 BC 边界
- 共享类型快速演化 → 用 Published Language 替代
- 使用方无法联合管理 → 避免 Shared Kernel
这是 V2 B3 分解的反向工程化——分解失败时不要硬拆,集中管理反而更好。
判断 Shared Kernel 是否健康 = 内核 ≤ 10 个类 + 修改频率 ≤ 1次/季度 + 所有使用方同步升级。 判断失败 = 内核不断膨胀 + 频繁破坏性改动 + 团队抱怨耦合。
相关链接
- 9 种 BC 关系——Shared Kernel 是其中之一
- Customer-Publisher——另一种共享方式(OHS + PL)
- Bounded Context——Shared Kernel 的边界
- [V3 涌现作为] · 分解——分解的边界
- 源典 IDDD Ch 3——Vernon 原书精读
- 源典 SE@G Ch 21——依赖管理原则