返回博客

开发日记:从第 1 行代码到 6000+ 测试

本文是 coomia-dip 项目从立项到首个公测版本的完整开发日记。我们用 14 个月的时间,从一行 print("hello ontology") 出发,构建了一个对标 Palantir Foundry 的本体驱动智能决策 PaaS 平台。截至本文撰写时,项目已拥有超过 6000 个自动化测试用例、覆盖 8 个架构分层(Layer),代码行数突破 15 万行。这篇文章将以时间线的方式回顾关键里程碑、技术抉择、踩过的坑,以及我们从中学到的经验教训。

Coomia发布于 2026年2月16日15 分钟阅读
分享本文Twitter / X

系列:S14 工程实录 · 第 1 篇 | 难度:中级 | 阅读时间:15 分钟

开发日记:从第 1 行代码到 6000+ 测试

#TL;DR

本文是 coomia-dip 项目从立项到首个公测版本的完整开发日记。我们用 14 个月的时间,从一行 print("hello ontology") 出发,构建了一个对标 Palantir Foundry 的本体驱动智能决策 PaaS 平台。截至本文撰写时,项目已拥有超过 6000 个自动化测试用例、覆盖 8 个架构分层(Layer),代码行数突破 15 万行。这篇文章将以时间线的方式回顾关键里程碑、技术抉择、踩过的坑,以及我们从中学到的经验教训。

#1. 起源:为什么要做这件事

#1.1 Palantir Foundry 的启示

2024 年初,团队在为一家制造业客户做数据中台选型时,深入研究了 Palantir Foundry。我们被它的核心理念——"本体(Ontology)驱动一切"——深深震撼。传统的数据平台停留在"表-列-行"的抽象层次,而 Foundry 将业务概念(设备、工单、供应商)提升为一等公民,所有的数据管道、分析、权限、操作都围绕这些本体对象展开。

然而,Foundry 有两个致命缺陷:一是价格——起步价数百万美元/年;二是数据主权——SaaS 模式意味着数据出境。对于国内的制造业和金融客户,这都是不可接受的。

#1.2 立项决策

经过两周的可行性分析,我们得出结论:Foundry 的核心架构并非不可复制,关键在于 Ontology Runtime、Schema Registry、Action Engine 三大核心组件。我们决定启动 coomia-dip 项目——一个可私有化部署、开源友好的 Palantir Foundry 替代方案。

#1.3 团队组建

初始团队只有 4 个人:

  • 1 名架构师(负责整体设计和 Control Layer)
  • 1 名后端工程师(负责 Data Layer)
  • 1 名 AI 工程师(负责 Intelligence Layer)
  • 1 名全栈工程师(负责 SDK 和前端)

这个精简的团队配置,后来被证明既是优势(决策快、沟通成本低)也是劣势(人手不足时只能靠加班)。

#2. 第一个月:架构奠基(Day 1 – Day 30)

#2.1 分层架构的诞生

第一周的全部时间都花在了架构讨论上。我们最终确定了 8 个 Layer 的架构:

Layer职责技术栈
A - Platform Deployment & Ops部署运维Docker Compose, Python
B - Control Layer控制层Spring Boot 3.x, Java 21, gRPC
C - Data Layer数据层Quarkus 3.x, Iceberg+Nessie
D - Reasoning & Decision推理决策Python, FastAPI, gRPC
E - Agent RuntimeAgent 运行时Python, FastAPI, Temporal
F - Pipeline & Orchestration管道编排Quarkus 3.x, DolphinScheduler
G - Metadata & Governance元数据治理Java, Gradle
H - SDK & Developer ExperienceSDK 开发者体验Python SDK, TypeScript

为什么是 8 个 Layer?因为我们相信"关注点分离"。每个 Layer 有独立的生命周期、技术栈选择自由度,以及独立部署的能力。当然,后来我们发现 8 个 Layer 在开发期太重了——但这是后话(详见 S14-03)。

#2.2 第一行代码

Python
# ontology_sdk/__init__.py - 2024-02-15
print("hello ontology")
__version__ = "0.0.1"

这行代码今天还在 git 历史中。它提醒我们,每个庞大的系统都始于一个简单的起点。

#2.3 技术选型的关键决策

gRPC over REST:内部服务之间全部使用 gRPC。这个决策在第一周就确定了,原因是:

  • 强类型契约(Protobuf IDL)
  • 双向流
  • 代码生成减少重复劳动
  • 性能(二进制序列化 + HTTP/2 多路复用)

Gradle over Maven:Java 项目统一使用 Gradle。Maven 的 XML 配置在多模块项目中过于冗长。

Python for Intelligence Layer:推理引擎和 Agent 运行时用 Python + FastAPI,因为 AI/ML 生态系统几乎全在 Python。

#3. 第二到第三个月:核心组件(Day 31 – Day 90)

#3.1 Ontology Runtime v1

Ontology Runtime 是整个平台的心脏。它负责:

  • 管理 ObjectType、LinkType 的定义
  • 维护 Object 实例的生命周期
  • 提供 OQL(Ontology Query Language)查询接口

第一个版本非常简陋——内存中的 HashMap 存储,没有持久化,没有事务。但它跑通了核心流程:定义一个 ObjectType → 创建 Object → 通过 OQL 查询。

#3.2 Schema Registry

Schema Registry 管理所有本体类型的元数据。我们参考了 Confluent Schema Registry 的设计,但做了本体化的扩展:

  • 支持 ObjectType、LinkType、ActionType 三种一等类型
  • 版本管理(每次修改生成新版本,旧版本不可变)
  • 兼容性检查(新版本必须向后兼容)

#3.3 第一个集成测试

Day 60,我们跑通了第一个端到端集成测试:

Code
1. 通过 SDK 创建 ObjectType "Device"
2. 为 Device 添加属性 name, status, location
3. 创建 3 个 Device 实例
4. 通过 OQL 查询 status == "running" 的设备
5. 验证返回 2 条结果

这个测试虽然简单,但它串联了 SDK → Control Layer → Data Layer 的完整链路。团队为此庆祝了一下——这是系统第一次"活"了起来。

#3.4 测试策略初定

从一开始,我们就决定走"测试驱动"的路线。每个 Layer 独立维护自己的测试套件:

  • 单元测试:覆盖核心业务逻辑
  • 集成测试:验证 Layer 内组件协作
  • 契约测试:验证 gRPC 接口兼容性
  • 端到端测试:跨 Layer 的完整业务流程

Day 90 时,测试用例数量达到 约 400 个

#4. 第四到第六个月:功能爆发(Day 91 – Day 180)

#4.1 Action Engine

Action Engine 是 coomia-dip 的"执行器"。它允许用户定义 Action(如"审批工单"、"调整库存"),并在执行时进行权限检查、参数校验、副作用管理。

Action Engine 的核心设计理念是 "可逆性":每个 Action 必须定义 applyrevert 两个方法。这借鉴了 Saga 模式——在分布式环境中,如果一个操作失败了,系统需要能够回滚已完成的步骤。

#4.2 Rule Engine

Rule Engine 实现了前向链推理。用户可以定义规则(如"当设备温度 > 80°C 且运行时间 > 24h 时,触发维护工单"),系统会在数据变更时自动评估规则并执行相应的 Action。

我们最初尝试了 Drools,但发现它太重了——引入了整个 KIE 生态系统。最终我们自研了一个轻量级的规则引擎,基于 Rete 算法的简化版本。

#4.3 数据管道

数据管道是将外部数据导入 coomia-dip 的通道。我们集成了 DolphinScheduler 作为调度引擎,支持:

  • 批量导入(CSV、JSON、Parquet)
  • 增量同步(CDC 通过 Debezium)
  • 实时流(Kafka Consumer)

#4.4 权限模型

权限模型是所有企业级平台的核心。我们实现了三层权限:

  • RBAC(基于角色的访问控制)
  • ABAC(基于属性的访问控制)
  • 行级权限(基于本体属性的数据过滤)

这三层可以组合使用。例如:"财务部门(RBAC)可以查看(ABAC:只读)本部门(行级:department == user.department)的工单"。

#4.5 测试数量爆发

Day 180 时,测试用例数量达到 约 1800 个。增长最快的是 Action Engine 和 Rule Engine 的测试——因为它们的边界条件极多。

#5. 第七到第九个月:稳定性攻坚(Day 181 – Day 270)

#5.1 性能问题浮现

随着测试数据量增加,性能问题开始暴露:

  • OQL 查询在 10 万级数据量下响应超过 5 秒
  • Action Engine 的并发执行存在死锁风险
  • Rule Engine 的规则评估在复杂规则集下呈指数增长

#5.2 OQL 查询优化

OQL 查询优化是这个阶段最大的技术挑战(详见 S14-09)。核心改进包括:

  • 引入查询计划优化器
  • 实现谓词下推到存储层
  • 添加查询结果缓存
  • 优化 JOIN 策略(从嵌套循环改为 Hash Join)

优化后,同样的查询从 5 秒降到了 200ms——25 倍的提升。

#5.3 并发控制

Action Engine 的死锁问题源于多个 Action 同时修改同一个 Object。我们引入了乐观并发控制(OCC):

  • 每个 Object 维护版本号
  • Action 执行时检查版本号
  • 冲突时自动重试(最多 3 次)

#5.4 存储架构变迁

存储架构经历了三次大的变迁:

  1. v1:PostgreSQL + MinIO(简单,但查询能力有限)
  2. v2:PostgreSQL + ClickHouse + MinIO(OLAP 性能好,但运维复杂)
  3. v3:Doris + Iceberg/Nessie + MinIO(统一 OLTP/OLAP,版本化存储)

每次变迁的具体原因和过程,详见 S14-02 和 S14-04。

#5.5 测试持续增长

Day 270 时,测试用例数量达到 约 3500 个。我们开始引入性能测试和压力测试——用 Locust 模拟 1000 并发用户的场景。

#6. 第十到第十二个月:产品化(Day 271 – Day 365)

#6.1 SDK 1.0

Python SDK 是用户与 coomia-dip 交互的主要方式。SDK 1.0 的设计目标是:

  • 直觉性:API 命名要让从未用过本体平台的开发者也能猜出用法
  • 类型安全:所有 API 都有完整的类型注解,IDE 可以提供自动补全
  • 渐进式:简单场景一行代码搞定,复杂场景通过 Builder 模式组合
Python
from ontology_sdk import OntoPlatform

platform = OntoPlatform.connect("localhost:8080")

# 一行代码创建对象
device = platform.objects.create("Device", name="CNC-001", status="running")

# 一行代码查询
running_devices = platform.objects.query("Device").where(status="running").list()

# 一行代码执行操作
platform.actions.execute("MaintenanceCheck", target=device)

#6.2 部署方案

我们提供了三种部署方案:

  • 开发模式docker compose up,单机启动所有服务
  • 测试模式:3 节点 Docker Swarm,模拟分布式环境
  • 生产模式:Kubernetes + Helm Chart,支持水平扩展

#6.3 文档体系

文档是产品化的关键。我们建立了完整的文档体系:

  • 快速开始(5 分钟跑通)
  • API 参考
  • 架构指南
  • 行业案例
  • 系列技术文章(就是您正在读的这个系列)

#6.4 测试里程碑

Day 365 时,测试用例数量达到 约 5200 个。测试通过率维持在 99.5% 以上。

#7. 第十三到第十四个月:打磨与开源(Day 366 – Day 420)

#7.1 AI 辅助开发的引入

从第十三个月开始,我们大规模引入 AI 辅助开发(详见 S14-11)。Claude 被用于:

  • 代码审查
  • 测试用例生成
  • 文档撰写
  • Bug 调试

AI 的引入显著加速了测试用例的编写速度——从平均每天 15 个提升到 40 个。

#7.2 开源准备

开源不仅仅是把代码放到 GitHub 上。我们做了大量准备工作:

  • 代码审计(移除硬编码密钥、内部 IP)
  • 许可证选择(Apache 2.0)
  • 贡献者指南
  • Issue 模板
  • CI/CD 流水线(GitHub Actions)

#7.3 6000+ 测试的意义

截至 Day 420,测试用例数量突破 6000 个。这些测试分布如下:

类别数量占比
单元测试320053%
集成测试180030%
端到端测试60010%
性能测试2504%
契约测试1503%

6000+ 测试不仅仅是一个数字。它代表的是:

  • 每次提交都有信心不会破坏现有功能
  • 重构时有安全网(我们做了 3 次大规模重构,全靠测试兜底)
  • 新成员入职时有"可执行的文档"
  • 回归 Bug 几乎降到零

#8. 关键里程碑时间线

时间里程碑测试数
Day 1第一行代码0
Day 30架构设计完成,Protobuf 定义完成50
Day 60第一个端到端测试通过200
Day 90Ontology Runtime v1 完成400
Day 120Action Engine v1 完成800
Day 150Rule Engine v1 完成1200
Day 180数据管道 + 权限模型完成1800
Day 210OQL 查询优化完成2400
Day 240存储架构迁移到 Doris2800
Day 270性能测试 + 压力测试引入3500
Day 300SDK 1.0 Beta4200
Day 330部署方案 + 文档体系4800
Day 365首个公测版本发布5200
Day 4206000+ 测试里程碑6000+

#9. 最深刻的教训

#9.1 过早优化 vs. 过晚优化

我们在存储架构上犯了"过早优化"的错误——第二个月就引入 ClickHouse,结果发现它在我们的场景下并不比 Doris 好,反而增加了运维复杂度。但在 OQL 查询优化上,我们又犯了"过晚优化"的错误——等到用户抱怨才开始优化,修复成本远高于在设计阶段就考虑性能。

教训:先让它工作,再让它正确,最后让它快速。但"最后"不意味着"直到用户投诉"。

#9.2 测试是投资,不是成本

每次有人提议"先跳过测试赶功能"时,我们都坚持写测试。这在短期内确实拖慢了交付速度,但在第七个月性能攻坚期,这些测试救了我们——它们让我们能够大胆重构而不怕破坏功能。

教训:测试的 ROI 在第六个月后开始显现,之后呈指数增长。

#9.3 4 个人的沟通成本被低估了

虽然 4 个人的团队很精简,但当每个人负责不同的 Layer 时,接口变更的沟通成本远超预期。我们后来引入了 Protobuf 作为"接口契约",任何接口变更必须先提 PR 修改 .proto 文件,其他人审查通过后才能实施。

教训:人少不代表不需要流程。

#10. 写在最后

从第 1 行代码到 6000+ 测试,coomia-dip 的开发之旅远比这篇文章能描述的更加曲折。我们经历了技术方案的反复推翻、深夜的 Bug 调试、性能瓶颈的焦虑,也享受过每一个"跑通了!"的瞬间。

这个系列的后续文章将深入展开每一个关键决策和技术挑战。如果你正在做类似的事情——构建一个复杂的平台级产品——希望我们的经验能帮助你少走一些弯路。

#Key Takeaways

  1. 架构设计要留有余地:分层架构在初期很理想,但在团队规模和开发效率之间需要平衡
  2. 测试是最好的投资:6000+ 测试让团队有信心进行大规模重构
  3. 小团队也需要流程:4 个人的团队也需要接口契约和代码审查
  4. 存储选型要谨慎:每次存储架构变迁的成本都比预期高 3-5 倍
  5. 性能优化要有计划:不要等到用户投诉,也不要过早优化

#Next Article

下一篇:S14-02 为什么放弃 ClickHouse — 我们将详细讲述存储选型中的 ClickHouse 之殇,以及为什么 Doris 最终胜出。

Tags: #coomia-dip #开发日记 #架构设计 #测试策略 #工程实录 #Palantir替代