

























探讨领域驱动设计(DDD)与本体论建模(Ontology)之间的本质差异,搞清其背后的理论体系和运行机制。
复杂业务系统的建模方法与开发方式可以分为两条路线:
二者在表面上都涉及“对象、关系与行为”,但其实际解决的问题层级截然不同:
flowchart TB BIZ["复杂业务系统建模"]:::root L1["L1 · 应用级建模 (DDD)<br/>━━━━━━━━━━━━<br/>解决单服务内部逻辑自洽"]:::layer1 L2["L2 · 企业级建模 (Ontology)<br/>━━━━━━━━━━━━<br/>解决跨系统语义与数据治理"]:::layer2 DDD["DDD<br/>充血模型 / 限界上下文<br/>分层架构 / 领域事件"]:::ddd ONTO["Ontology<br/>ObjectType / LinkType<br/>ActionType / Function"]:::onto BIZ --> L1 BIZ --> L2 L1 --> DDD L2 --> ONTO classDef root fill:#37474F,stroke:#263238,stroke-width:2px,color:#ECEFF1 classDef layer1 fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px,color:#BF360C classDef layer2 fill:#B2DFDB,stroke:#00796B,stroke-width:2px,color:#004D40 classDef ddd fill:#FFCDD2,stroke:#C62828,stroke-width:2px,color:#B71C1C classDef onto fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px,color:#1B5E20
误用二者的典型代价是:用 DDD 做全企业模型会导致架构僵化;而用 Ontology 做纯应用框架则会显得过于沉重。只有各司其职,才能发挥其最大价值。
二者都有一套自己的"基础词汇",下面把对齐项放在一起看。
| 关注点 | DDD | Ontology(Palantir) | 关键差异 |
|---|---|---|---|
| 实体 | Entity(领域层中带 ID 的对象) | ObjectType + 实例 | DDD 实体是代码类;Ontology Object 是平台一等公民 |
| 值对象 | Value Object(不可变、按值判等) | Property 上的 Value Type(约束、单位、枚举) | DDD 值对象封装行为;Ontology Value Type 偏数据约束 |
| 关系 | 实体 / 聚合根间的引用(聚合内强引用 + 聚合外 ID 引用) | LinkType(独立一等类型,带语义、基数、属性) | Ontology 关系本身就是"对象",可以挂属性 |
| 聚合根 | Aggregate Root(保证内部不变量) | ⊘ 无直接对应——Ontology 不假设强一致性边界 | DDD 聚合 = 事务一致性边界;Ontology 一致性由 Action 显式约束 |
| 行为 | 聚合根 / 实体 / 领域服务的方法 | ActionType(声明式:参数 + 校验 + 副作用 + 权限 + 审计) | DDD 行为编码在类里;Ontology 行为是平台契约 |
| 业务规则 | 充血模型的方法 + 领域服务 | ActionType 校验 + Function(外部 / 内部规则) | DDD 规则与对象共生;Ontology 规则与对象解耦但绑定 |
| 领域事件 | Domain Event(应用层发布) | 写后事件 / 流(依据 ActionType 自动产生审计与下游事件) | Ontology 事件天然带审计、自动派发 |
| 边界 | Bounded Context(限界上下文,按业务边界) | 通常按 ObjectType + 权限组划分,不强制"上下文" | DDD 强调边界清晰;Ontology 强调跨边界统一语义 |
| 统一语言 | Ubiquitous Language(团队术语表 + 代码命名) | Ontology 本身就是企业级的统一语言 | DDD 限于一个团队 / 上下文;Ontology 跨整个企业 |
| 权限 | 外挂在应用层(Spring Security、网关) | 内建于 ObjectType / ActionType,随每次调用自动生效 | Ontology 权限是一等公民,DDD 默认不管 |
| 审计 | 应用层手工埋点 / AOP | ActionType 调用自动落审计日志 | Ontology 把审计变成"无需努力即默认开启" |
flowchart TB subgraph DDDStack["DDD 抽象栈(代码即模型)"] direction TB DDD_App["应用代码<br/>(Java / Go / Python)"]:::dddTop DDD_Lang["编程语言<br/>(OOP / FP)"]:::dddMid DDD_Run["运行时<br/>(JVM / OS / 容器)"]:::dddBot DDD_App --> DDD_Lang --> DDD_Run end subgraph ONTOStack["Ontology 抽象栈(平台即模型)"] direction TB ONTO_Sem["语义层<br/>(Ontology DSL / 元数据)"]:::ontoTop ONTO_Plat["平台<br/>(Foundry / OSv2 / OMS / Funnel)"]:::ontoMid ONTO_Infra["基础设施<br/>(数据湖 / OLTP / OLAP)"]:::ontoBot ONTO_Sem --> ONTO_Plat --> ONTO_Infra end classDef dddTop fill:#FFCDD2,stroke:#C62828,stroke-width:2px,color:#B71C1C classDef dddMid fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px,color:#BF360C classDef dddBot fill:#F5F5F5,stroke:#616161,stroke-width:2px,color:#212121 classDef ontoTop fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px,color:#1B5E20 classDef ontoMid fill:#B2DFDB,stroke:#00796B,stroke-width:2px,color:#004D40 classDef ontoBot fill:#F5F5F5,stroke:#616161,stroke-width:2px,color:#212121 style DDDStack fill:#FFEBEE,stroke:#C62828,stroke-width:2px,color:#000 style ONTOStack fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px,color:#000
DDD 的载体是"程序"——业务模型靠源代码表达,靠编译器和测试保证一致性,部署到 JVM / 容器中执行。
Ontology 的载体是"平台"——业务模型靠元数据声明(ObjectType / LinkType / ActionType),由平台保证一致性,由专门的语义层服务(如 OSv2、OMS、Funnel)执行。
这一抽象层级的差异,决定了二者在"表达力 / 工程成本 / 跨系统统一性"上的所有不同。
二者背后的本体观(哲学层面)截然不同。
| 哲学立场 | 工程范式 | 代表 |
|---|---|---|
| 实体本体论:世界由对象构成,关系是对象的附属 | ER / OOP / DDD | 关系数据库、Java / C# 类、DDD 聚合 |
| 关系 / 过程本体论:关系与变化更基本,对象是关系的节点 | 知识图谱 / Ontology / 函数式 | RDF / OWL、Palantir Ontology、F# 函数式 DDD |
DDD 继承了 OOP 的实体本体观——对象是建模的中心,关系靠对象引用(聚合内)或 ID 引用(聚合外)表达;行为是对象的方法。
Ontology 站在关系本体观一侧——LinkType 是独立的一等公民,可以挂属性、可以被查询、可以参与 Action;对象是"关系网络中的节点",而不是建模的中心。
工程后果:DDD 适合表达"对象内部的强一致性规则";Ontology 适合表达"对象之间的复杂关系网络与跨域决策"。试图用 DDD 表达"任意两个对象间的 N 种关系且关系本身有属性",会让聚合根膨胀;试图用 Ontology 表达"聚合内部 7 条不变量的强一致性事务",会发现它的最终一致性语义不直接支持。
Ontology 不仅是本体论的实现,Palantir 把它扩展为"本体—认识—实践"三层(详见 ../ontology-research/技术原理介绍.md 1.2 节):
| 哲学层 | Palantir 对应 | DDD 对应 |
|---|---|---|
| 本体论(有什么) | ObjectType + LinkType + Property | 实体 + 值对象 + 聚合 |
| 认识论(如何认识 / 推理) | ActionType + Function + Models / Analytics | 领域服务 + 领域事件 + 规则引擎 |
| 实践论(如何变成行动) | AIP Agent + 审批流 + 写回 | 应用服务编排 + 工作流引擎 |
DDD 主要回答本体论与认识论,把"实践论"留给业务方与应用层。Ontology 的雄心更大——它要把三层合到同一个语义平台、同一套权限、同一条审计链路上。
下面把二者在工程上的具体形态摆在一起,差异立刻清晰。
DDD 写法(Java / Spring Boot):
// 实体(聚合根)
public class Vehicle {
private VehicleId id;
private String model;
private VehicleStatus status;
private List<RequiredPart> requiredParts; // 聚合内强引用
private ProductionLineId assignedLine; // 聚合外用 ID
public void startProduction(ProductionLine line, InventoryView inventory) {
if (!inventory.hasAllParts(this.requiredParts))
throw new IllegalStateException("缺料");
if (!line.isIdle())
throw new IllegalStateException("产线繁忙");
this.status = VehicleStatus.IN_PRODUCTION;
this.assignedLine = line.getId();
addDomainEvent(new VehicleStartedProductionEvent(this.id, line.getId()));
}
}
Ontology 写法(Palantir 风格的伪代码,详见 ../ontology-research/数据存储与使用方式对比.md):
// ObjectType 声明
{ "ObjectType": "Vehicle", "properties": { "model": ..., "status": ... } }
// LinkType 声明(关系是一等公民)
{ "LinkType": "REQUIRES_PART",
"from": "Vehicle", "to": "Part",
"properties": { "mandatory": "boolean", "quantity": "integer" } }
// ActionType 声明(行为是一等公民)
{ "ActionType": "startProduction",
"subject": "Vehicle",
"params": { "line": "ProductionLine" },
"preconditions": [
{ "rule": "allRequiredPartsInStock(vehicle)" },
{ "rule": "line.status == 'IDLE'" }
],
"effects": [
{ "set": "vehicle.status = 'IN_PRODUCTION'" },
{ "link": "vehicle ASSIGNED_TO line" }
],
"permissions": ["role:PLANT_MANAGER"],
"audit": "auto"
}
核心差异:
| 维度 | DDD 方法 | Ontology 方法 |
|---|---|---|
关系 requiredParts |
写为聚合内集合 | 写为独立 LinkType 实体 |
行为 startProduction |
写为聚合根方法 | 写为 ActionType 声明 |
| 校验 | 方法体内 if/else + 异常 | preconditions 声明 |
| 权限 | 外挂 @PreAuthorize |
ActionType 内置 permissions |
| 审计 | 手工 audit.log(...) 或 AOP |
ActionType 内置 audit:auto |
| 外部消费 | 必须再写一份 OpenAPI / RPC 契约 | OSDK / 平台 API 自动衍生 |
flowchart TB subgraph DDDSide["DDD:多服务各自实现,事件解耦"] direction LR D_Order["订单服务<br/>充血 Order"]:::dddNode D_Pay["支付服务<br/>充血 Payment"]:::dddNode D_Stock["库存服务<br/>充血 Stock"]:::dddNode D_MQ[("消息队列<br/>Kafka / RocketMQ")]:::mq D_Order --> D_MQ D_Pay --> D_MQ D_Stock --> D_MQ D_MQ --> D_Order D_MQ --> D_Pay D_MQ --> D_Stock end subgraph ONTOSide["Ontology:共享语义底座,调用即写回"] direction LR O_Order["Order<br/>ObjectType"]:::ontoObj O_Pay["Payment<br/>ObjectType"]:::ontoObj O_Stock["Stock<br/>ObjectType"]:::ontoObj O_Action["Action / Function<br/>(一等公民)"]:::ontoAct O_Sem["Ontology 语义层<br/>权限 / 审计 / 链接"]:::ontoSem O_Order --- O_Action O_Pay --- O_Action O_Stock --- O_Action O_Action --- O_Sem end classDef dddNode fill:#FFCDD2,stroke:#C62828,stroke-width:2px,color:#B71C1C classDef mq fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px,color:#BF360C classDef ontoObj fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px,color:#1B5E20 classDef ontoAct fill:#FFF9C4,stroke:#F9A825,stroke-width:2px,color:#F57F17 classDef ontoSem fill:#B3E5FC,stroke:#0277BD,stroke-width:2px,color:#01579B style DDDSide fill:#FFEBEE,stroke:#C62828,stroke-width:2px,color:#000 style ONTOSide fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px,color:#000
DDD 体系下,三个服务各有一套领域模型,靠领域事件 + 上下文映射协作;每跨一个上下文都要做防腐层翻译。
Ontology 体系下,三个领域共享同一套语义底座,跨系统调用即在同一个 Ontology 内调用 Action——不需要"防腐层",因为根本没有"腐"可防。
代价对比:DDD 的代价是"跨上下文翻译成本";Ontology 的代价是"必须先有一个像 Foundry 这样的平台"。前者可以用 Spring + Kafka 起步,后者需要数百万级的平台采购或自建。
| 业务现象 | DDD 表达力 | Ontology 表达力 |
|---|---|---|
| 单聚合内强一致性事务(如订单状态机) | ★★★★★ 充血模型直接表达 | ★★★ 需要把多个 Action 组合 |
| 跨聚合 / 跨服务的关系网络(如供应链上下游) | ★★ 必须用 ID 引用,难以查询 | ★★★★★ LinkType 是一等公民,可查询、可挂属性 |
| 同一字段的多种含义(同名异义) | ★★★★★ 用限界上下文天然解决 | ★★★ 必须显式区分 ObjectType |
| 复杂业务规则与状态机 | ★★★★★ 充血方法 + 状态枚举 | ★★★★ ActionType 校验 + Function |
| 企业级权限治理 | ★★ 外挂、易遗漏 | ★★★★★ 内置、随调用生效 |
| 全链路审计 | ★★ 需手工埋点 | ★★★★★ 自动 |
| 复杂跨实体查询(图遍历) | ★ 必须靠 JOIN | ★★★★★ 沿 LinkType 走 |
| AI Agent 在权限下安全操作 | ★★ 工程负担大 | ★★★★★ Ontology 是 AI 的语义底座 |
| 单元测试领域逻辑 | ★★★★★ new Order().pay() | ★★★ 需在平台环境运行 |
| 团队多语言异构落地 | ★★★★★ 各语言各写一套 | ★★ 锁定平台技术栈 |
虽然抽象层级不同,二者仍有大量共识:
| 共识 | DDD 表达 | Ontology 表达 |
|---|---|---|
| 业务语言贯穿模型 | 统一语言(Ubiquitous Language) | Ontology 即企业级统一语言 |
| 行为绑定数据 | 充血模型(方法绑在聚合根上) | ActionType 绑在 ObjectType 上 |
| 拒绝业务规则散落 | 规则在领域层 | 规则在 ActionType / Function |
| 边界保护不变量 | 聚合一致性边界 | ActionType preconditions + 权限 |
| 显式建模关系与事件 | 实体关系 + 领域事件 | LinkType + 写后事件 |
二者并非对立:在 Palantir 体系内,单个 Ontology 内的 ActionType / Function 实现仍可遵循 DDD 充血模型;反过来,DDD 项目在跨多个限界上下文做企业级统一时,可以借鉴 Ontology 的"关系 / 行为一等公民"思想引入图模型或语义层(如 GraphQL Federation + 共享词表)。
%%{init: {'flowchart': {'rankSpacing': 20, 'nodeSpacing': 50, 'padding': 10}}}%% flowchart TD Start(["新项目 / 现有系统重构"]):::start Q1{"业务复杂度<br/>足够高?"}:::question Simple["朴素 MVC<br/>+ 关系数据库"]:::simple Q2{"跨多事业部?<br/>强合规审计?<br/>需要 LLM 在权限下操作?"}:::question Q3{"有平台预算<br/>或自建语义层意愿?"}:::question DDD["选 DDD<br/>充血模型 + 分层架构"]:::ddd ONTO["选 Ontology<br/>(Foundry / 自建语义层)"]:::onto Hybrid["混合方案<br/>(Ontology + DDD)<br/>详见《应用结合》"]:::hybrid Start --> Q1 Q1 -->|否| Simple Q1 -->|是| Q2 Q2 -->|否| DDD Q2 -->|是| Q3 Q3 -->|否| DDD Q3 -->|"是,且需要单服务内部规则强表达"| Hybrid Q3 -->|"是,且追求全企业统一"| ONTO classDef start fill:#37474F,stroke:#263238,stroke-width:2px,color:#ECEFF1 classDef question fill:#FFF9C4,stroke:#F9A825,stroke-width:2px,color:#ff3300 classDef simple fill:#ECEFF1,stroke:#607D8B,stroke-width:2px,color:#263238 classDef ddd fill:#FFCDD2,stroke:#C62828,stroke-width:2px,color:#B71C1C classDef onto fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px,color:#1B5E20 classDef hybrid fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px,color:#BF360C
| 维度 | DDD | Ontology |
|---|---|---|
| 解决的核心问题 | 单应用内部代码如何对齐业务 | 企业级语义、权限、审计如何统一 |
| 载体 | 应用代码(OOP / FP) | 平台(语义层 + 元数据) |
| 建模哲学 | 实体本体论 | 关系 / 过程本体论 + 三层哲学 |
| 强项 | 单聚合一致性、可测试性、低成本 | 跨系统统一、权限审计、AI 协作 |
| 弱项 | 跨上下文协作成本高 | 平台门槛高、单聚合强一致性表达弱 |
| 典型工程 | Spring Boot + COLA | Palantir Foundry |
| 典型场景 | 微服务领域建模 | 企业中台 / 决策系统 / AI 平台 |
两者并非互斥——在一个真实的企业级 AI 决策系统里,二者经常以"Ontology 作知识层 + DDD 作执行层"的方式协作。详见DDD与Ontology应用结合.md。
参考文档
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。