3. 限界上下文基础:DDD中的限界上下文定义、通用语言与上下文映射
在领域驱动设计(DDD)的战略设计中,限界上下文(Bounded Context)是最核心的战术单元。它既是模型的边界,也是团队协作的契约。理解限界上下文,是划分DAG任务调度服务边界的前提。
3.1 限界上下文的定义与本质
限界上下文是一个显式的边界,领域模型在这个边界内部具有统一的含义和生命周期。边界之外,模型可能以不同的形式存在,甚至完全不存在。
| 维度 | 说明 | DAG调度场景类比 |
|---|---|---|
| 语义边界 | 同一个术语在不同上下文中含义不同 | “任务”在调度上下文指DAG节点,在监控上下文指执行记录 |
| 模型边界 | 实体、值对象、聚合只在本上下文中完整 | DAG拓扑结构只在调度上下文中维护 |
| 团队边界 | 一个上下文通常由一个团队负责 | 调度团队与执行团队可能分属不同上下文 |
| 技术边界 | 数据库、服务、部署单元独立 | 调度服务与执行服务可独立部署 |
核心原则:限界上下文不是按技术分层(如Controller/Service/DAO)划分的,而是按业务概念的一致性划分的。同一个“任务”概念,在调度、执行、监控三个上下文中,其属性、行为、生命周期完全不同。
3.2 通用语言:团队沟通的基石
通用语言(Ubiquitous Language)是限界上下文内部所有成员(领域专家、开发、测试、产品)共同使用的语言。它消除了“业务说A,技术说B”的翻译成本。
- 词汇统一:所有文档、代码、讨论使用相同的术语。
- 模型驱动:代码中的类名、方法名、属性名直接反映通用语言。
- 持续演进:当发现术语歧义时,优先调整通用语言,而非在代码中做映射。
DAG调度场景示例:
调度上下文通用语言:DAG(有向无环图)、节点(Node)、边(Edge)、拓扑排序、调度周期。
执行上下文通用语言:任务实例(TaskInstance)、执行器(Executor)、状态(Pending/Running/Success/Failed)、重试次数。
两个团队在沟通时,必须明确当前使用的是哪个上下文的语言。
调度上下文通用语言:DAG(有向无环图)、节点(Node)、边(Edge)、拓扑排序、调度周期。
执行上下文通用语言:任务实例(TaskInstance)、执行器(Executor)、状态(Pending/Running/Success/Failed)、重试次数。
两个团队在沟通时,必须明确当前使用的是哪个上下文的语言。
3.3 上下文映射:连接边界的模式
当多个限界上下文需要协作时,必须定义它们之间的映射关系。上下文映射(Context Map)描述了不同上下文如何相互通信、数据如何流转、模型如何转换。
| 映射模式 | 关系描述 | DAG调度适用场景 |
|---|---|---|
| 合作关系(Partnership) | 两个上下文协同完成一个流程,互相依赖 | 调度上下文与执行上下文:调度触发执行,执行回传状态 |
| 共享内核(Shared Kernel) | 共享部分模型,但保持边界 | 调度与监控共享“任务状态”枚举,但各自维护不同模型 |
| 客户-供应商(Customer-Supplier) | 上游(供应商)提供数据,下游(客户)按需消费 | 调度上下文向上游“元数据上下文”获取DAG定义 |
| 防腐层(Anti-Corruption Layer) | 下游上下文建立转换层,防止上游模型污染 | 调度上下文对接外部系统时,通过ACL隔离外部模型 |
| 开放主机服务(Open Host Service) | 以API形式暴露服务,供其他上下文调用 | 调度上下文提供REST API供前端或外部系统调用 |
| 发布语言(Published Language) | 使用标准格式(如JSON Schema)作为通信协议 | 调度上下文与执行上下文通过事件消息(Event)通信 |
| 分离方式(Separate Ways) | 两个上下文完全独立,无任何通信 | 调度上下文与用户权限上下文,仅在登录时交互一次 |
常见误区:不要试图在所有上下文之间建立“共享内核”。共享越多,耦合越深,边界越模糊。优先使用防腐层和开放主机服务来保持边界清晰。
3.4 限界上下文与DAG调度服务的映射关系
下图展示了DAG任务调度系统中,核心限界上下文之间的典型映射关系:
3.5 限界上下文的识别方法
在DAG任务调度系统中,识别限界上下文可以遵循以下步骤:
- 事件风暴(Event Storming):与领域专家一起,用便签纸贴出所有领域事件,按业务流程分组。
- 寻找概念边界:当同一个术语在不同分组中含义不同时,就是潜在的上下文边界。
- 识别聚合根:每个上下文内部,找出聚合根(Aggregate Root),作为模型入口。
- 定义上下文映射:明确上下文之间的通信模式(合作关系、客户-供应商、防腐层等)。
- 验证边界:检查是否满足“高内聚、低耦合”原则,一个上下文的变化不应引起另一个上下文的连锁修改。
DAG调度上下文识别案例:
在事件风暴中,团队发现“任务提交”事件在调度团队眼中是“DAG节点入队”,在执行团队眼中是“任务实例创建”。两个团队对“任务”的理解不同,因此调度上下文和执行上下文应该分离。调度上下文负责DAG拓扑和调度策略,执行上下文负责任务实例的生命周期管理。
在事件风暴中,团队发现“任务提交”事件在调度团队眼中是“DAG节点入队”,在执行团队眼中是“任务实例创建”。两个团队对“任务”的理解不同,因此调度上下文和执行上下文应该分离。调度上下文负责DAG拓扑和调度策略,执行上下文负责任务实例的生命周期管理。
3.6 限界上下文与微服务的关系
限界上下文是逻辑边界,微服务是物理边界。一个限界上下文可以对应一个或多个微服务,但通常建议一个限界上下文对应一个微服务,以保持模型的一致性。
| 对比维度 | 限界上下文 | 微服务 |
|---|---|---|
| 本质 | 业务概念边界 | 技术部署单元 |
| 粒度 | 由业务一致性决定 | 由团队规模和部署需求决定 |
| 通信 | 上下文映射模式 | REST/gRPC/消息队列 |
| 数据 | 模型边界内数据自治 | 数据库独立 |
| 团队 | 通常一个团队负责 | 通常一个团队负责 |
实践建议:在DAG调度系统初期,可以先按限界上下文划分模块(Module),随着业务复杂度增加,再逐步拆分为独立的微服务。避免过早拆分导致分布式复杂性失控。