3. 领域与子域:核心域、支撑域、通用域的定义与识别
在 DDD 战略设计中,领域(Domain)是组织要解决的业务问题空间。一个大型软件系统通常包含多个业务关注点,将这些关注点按业务价值与通用性拆分为更小的子域(Subdomain),是架构师的首要任务。本章将定义三种子域类型,并给出识别与划分的实操策略。
3.1 三种子域的定义与对比
根据业务的重要程度与通用性,子域分为三类:
| 类型 | 定义 | 业务价值 | 通用性 | 典型示例(电商) |
|---|---|---|---|---|
| 核心域 | 系统最关键的、提供核心竞争力的业务逻辑 | 极高,直接决定产品差异 | 低,通常为自研 | 订单履约、定价引擎、推荐算法 |
| 支撑域 | 为核心域提供必要支持,但本身不构成核心竞争力 | 中等,缺少则无法运转 | 中,可自研或外包 | 库存管理、物流调度、客服工单 |
| 通用域 | 行业通用、无业务差异化的能力 | 低,不产生竞争优势 | 高,可直接采购或使用开源 | 用户认证、支付网关、邮件通知 |
识别口诀:“核心域决定生死,支撑域保障运转,通用域避免重复造轮子。”
3.2 核心域的识别方法
核心域是架构投资的重点,识别时需回答以下问题:
- 业务差异点:如果没有这个模块,产品与竞品是否完全一样?
- 利润贡献:该模块是否直接驱动收入或用户留存?
- 变更频率:业务策略调整时,是否最常改动这里?
- 团队投入:最优秀的工程师是否集中在此?
案例:某外卖平台的核心域是“智能调度与预计送达时间”,而非“商家管理”或“支付”。调度算法直接决定配送效率和用户体验,是平台的核心资产。
3.3 支撑域与通用域的边界
支撑域与通用域容易混淆,区分标准是“是否需要定制化”:
- 支撑域:业务有特殊规则,无法直接使用现成方案。例如“库存锁定策略”因促销活动而异,需要自研。
- 通用域:行业标准实现,直接集成即可。例如“短信验证码”使用第三方 SDK,无需自研。
3.4 子域划分策略
子域划分不是一次性的,而是迭代演进的过程。推荐以下四步策略:
- 事件风暴(Event Storming):与业务专家一起,用领域事件串联业务流程,识别出聚合与限界上下文。
- 业务价值排序:对每个候选子域按“核心→支撑→通用”打分,标记优先级。
- 依赖关系分析:绘制子域间的依赖箭头,避免循环依赖;核心域应尽量少依赖其他子域。
- 限界上下文映射:为每个子域分配独立的限界上下文,确定上下文间的通信方式(RPC、事件、共享内核等)。
常见陷阱:不要将“技术分层”当作子域划分。例如“数据访问层”不是子域,“用户管理”才是。子域必须反映业务概念,而非技术组件。
3.5 子域关系与架构映射
下图展示了一个典型电商系统的子域划分与依赖关系:
3.6 子域划分的 Go 实践建议
在 Go 项目中,子域划分直接影响模块(module)与包(package)的组织:
- 每个子域一个 Go Module:例如
github.com/company/order、github.com/company/inventory,独立版本管理。 - 核心域模块使用内部包(internal):防止外部直接依赖核心实现细节。
- 通用域模块尽量薄:只做适配层,调用第三方 SDK,不包含业务逻辑。
- 支撑域模块可复用:如果多个核心域需要相同支撑能力,通过接口依赖倒置解耦。
Go 代码结构示例:
myapp/
├── order/ # 核心域:订单
│ ├── internal/
│ │ ├── domain/ # 实体、值对象、聚合
│ │ └── service/ # 领域服务
│ ├── api/ # 对外接口
│ └── go.mod
├── inventory/ # 支撑域:库存
│ ├── internal/
│ ├── api/
│ └── go.mod
├── auth/ # 通用域:认证
│ ├── api/
│ └── go.mod
└── go.work # 工作区统一管理
3.7 识别与划分的常见误区
| 误区 | 错误表现 | 正确做法 |
|---|---|---|
| 技术分层当作子域 | 将“数据访问层”或“缓存层”划为子域 | 子域必须对应业务概念,如“用户管理” |
| 所有子域同等对待 | 核心域与通用域投入相同资源 | 核心域投入 60% 以上资源,通用域尽量复用 |
| 子域划分一次完成 | 项目启动时强行划分所有子域 | 通过事件风暴迭代演进,逐步细化 |
| 忽略子域间通信 | 子域之间直接调用数据库 | 通过 API 或事件总线解耦 |
3.8 子域演进的持续验证
子域划分不是静态的,随着业务发展,支撑域可能升级为核心域,通用域也可能需要定制化。建议每季度进行一次子域健康度评审:
- 核心域的变更响应速度是否达标?
- 支撑域是否出现重复实现?
- 通用域是否有更好的开源替代?
总结:核心域是架构的心脏,支撑域是骨架,通用域是血液。清晰的子域划分让 Go 团队能够并行开发、独立部署,真正实现“高内聚、低耦合”的架构目标。