返回博客

架构决策记录:用 ADR 追踪每一个关键技术选型

TL;DR

Coomia发布于 2025年7月8日26 分钟阅读
分享本文Twitter / X

架构决策记录:用 ADR 追踪每一个关键技术选型

系列:S2 架构全景 · 第 15 篇 | 难度:中级 | 阅读时间:18 分钟

TL;DR

  • 架构决策记录(Architecture Decision Record, ADR)是一种轻量级文档方法,用于记录"为什么做出某个技术决策"。coomia-dip 使用 ADR 系统化地追踪从通信协议选择(gRPC vs REST)到构建工具选择(Gradle vs Maven)的每一个关键决策。
  • 好的 ADR 不只是记录"选了什么",更重要的是记录"为什么不选其他方案"。被否决的备选方案及其理由,对于未来的开发者理解架构上下文至关重要——它们回答了"当时为什么不用 X"这个最常见的问题。
  • ADR 是"活文档"而非"历史归档"。当技术环境变化导致原有决策需要修改时,不是删除旧 ADR,而是创建新 ADR 引用并取代旧 ADR。这样保持了完整的决策演进链路。

#1. 引言:被遗忘的"为什么"

#1.1 每个项目都有的问题

在软件项目的生命周期中,最常被问到的问题不是"这是怎么实现的"(代码回答了这个问题),而是"为什么选择这样实现"。

Code
"为什么内部通信用 gRPC 而不是 REST?"
"为什么 Java 项目用 Gradle 而不是 Maven?"
"为什么 Reasoning & Decision Layer 用 Python 而不是继续用 Java?"
"为什么用 Kafka 而不是 RabbitMQ?"
"为什么用 Doris 而不是 ClickHouse?"

这些问题在 coomia-dip 项目中每周都会被新加入的开发者提出。如果没有系统化的记录,回答通常依赖于"找到当时参与决策的人"——而当那个人离开团队后,这些宝贵的架构上下文就永远丢失了。

#1.2 ADR 是什么

ADR(Architecture Decision Record)是一种轻量级的结构化文档格式,用于记录重要的架构决策。每条 ADR 包含:

  • 背景:做决策时面临的情况和约束
  • 决策:最终选择了什么
  • 备选方案:考虑过但未选择的方案及理由
  • 后果:这个决策带来的正面和负面影响

ADR 不是设计文档、不是技术规格书、不是会议纪要——它是一种精炼的决策记录,通常 1-2 页即可完成。

#1.3 coomia-dip 的 ADR 实践

coomia-dip 项目将 ADR 作为架构治理的核心工具之一。在项目的 CLAUDE.md 中,有多条技术红线实际上就是关键 ADR 的执行结果:

Code
❌ 内部服务之间使用 REST/JSON(必须用 gRPC)     → ADR-001
❌ Reasoning & Decision Layer + Agent Runtime Layer 使用 Spring Boot(必须用 Python)    → ADR-003
❌ Java 项目使用 Maven(必须用 Gradle)           → ADR-005
❌ 绕过 Ontology 直接查库                        → ADR-007

每一条红线背后都有一个完整的 ADR,解释了决策的背景、理由和权衡。

#2. ADR 模板与格式

#2.1 coomia-dip ADR 模板

coomia-dip 使用以下标准化模板:

Markdown
# ADR-{编号}: {决策标题}

## 状态
{提议 | 已接受 | 已废弃 | 已取代 by ADR-XXX}

## 日期
YYYY-MM-DD

## 背景
{描述做决策时的情况、约束和需求}

## 决策
{明确声明做出的决策}

## 备选方案

### 方案 A: {名称}
- 优点: ...
- 缺点: ...
- 未选择原因: ...

### 方案 B: {名称}
- 优点: ...
- 缺点: ...
- 未选择原因: ...

## 后果

### 正面
- ...

### 负面
- ...

### 风险与缓解
- 风险: ...
  缓解: ...

## 参考
- {相关链接、文档、讨论}

#2.2 ADR 编号规则

coomia-dip 的 ADR 按领域分组编号:

范围领域示例
001-099通信与协议ADR-001 gRPC vs REST
100-199数据与存储ADR-101 Doris vs ClickHouse
200-299计算与运行时ADR-201 Python for Reasoning & Decision Layer
300-399构建与工程ADR-301 Gradle vs Maven
400-499测试与质量ADR-401 Testcontainers
500-599部署与运维ADR-501 Docker Compose
600-699安全与治理ADR-601 Ontology 强制路由
700-799SDK 与开发体验ADR-701 Python SDK 优先

#3. 核心 ADR 详解:通信协议

#3.1 ADR-001: gRPC 优于 REST 用于内部通信

状态: 已接受

日期: 2025-06-15

背景:

coomia-dip 由 8 个 Layer 组成,每个 Layer 是独立的服务或服务组。这些 Layer 之间需要高频、低延迟的通信。平台同时使用 Java(Control Layer + Data Layer)和 Python(Reasoning & Decision Layer + Agent Runtime Layer),因此通信协议必须具备跨语言能力。

需要考虑的约束:

  1. Java 和 Python 之间的序列化兼容性
  2. 通信延迟对派生属性计算链的影响(见 S2-07)
  3. 接口定义的版本管理和向后兼容
  4. 团队的学习成本和工具链成熟度

决策:

所有内部服务间通信必须使用 gRPC + Protobuf。REST/JSON 仅用于面向外部用户的 API 网关层。

备选方案:

方案 A: REST + JSON

  • 优点: 团队熟悉度高,调试工具丰富(Postman, curl),浏览器直接可测
  • 缺点: JSON 序列化/反序列化开销大(相比 Protobuf 慢 4-5 倍);无强类型接口定义,跨语言兼容性依赖文档而非代码;HTTP/1.1 每个请求一个连接,不支持双向流
  • 未选择原因: 在高频内部调用场景下(如派生属性级联计算可能触发数十次跨 Layer 调用),JSON 的序列化开销会从可忽略变为显著瓶颈

方案 B: REST + Protobuf

  • 优点: 保留 REST 语义,获得 Protobuf 序列化优势
  • 缺点: 非标准组合,工具链支持有限;仍然受限于 HTTP/1.1 的连接模型;代码生成工具不如 gRPC 生态完善
  • 未选择原因: 属于"两个世界的折衷",既没有 REST 的生态优势,也没有 gRPC 的完整能力

方案 C: Apache Thrift

  • 优点: 与 gRPC 类似的 IDL + 代码生成,性能优秀
  • 缺点: 社区活跃度不如 gRPC;流式传输能力较弱;云原生生态集成(Envoy, Istio)不如 gRPC
  • 未选择原因: gRPC 已成为云原生通信的事实标准,选择 Thrift 会增加与未来基础设施集成的成本

后果:

正面:

  • 跨语言接口兼容性由 Protobuf 编译器保证,消除了"文档与代码不一致"的问题
  • 序列化性能提升 4-5 倍,降低了派生属性级联计算的通信开销
  • 双向流支持为实时事件推送提供了原生能力
  • 与 Kubernetes 生态(gRPC 健康检查、负载均衡)天然集成

负面:

  • 调试难度增加——gRPC 使用二进制协议,无法像 JSON 一样直接用浏览器查看
  • 团队学习曲线——需要学习 Protobuf 语法和 gRPC 概念
  • 工具链要求——需要配置 protoc 编译器和各语言的代码生成插件

风险与缓解:

  • 风险: 调试困难影响开发效率 缓解: 引入 grpcurl 和 gRPC 反射 API,提供类似 curl 的调试体验;为开发环境配置 gRPC-Web 代理
  • 风险: Proto 文件变更导致跨语言不兼容 缓解: CI 流水线强制双语言编译和契约测试(见 S2-14)

#4. 核心 ADR 详解:技术栈选型

#4.1 ADR-201: Python 用于 Reasoning & Decision Layer + Agent Runtime Layer(智能决策层)

状态: 已接受

日期: 2025-07-02

背景:

Reasoning & Decision Layer(推理与决策)和 Agent Runtime Layer(Agent 运行时)需要处理以下任务:

  • 规则引擎评估
  • 机器学习模型推理
  • AI Agent 编排
  • 与 LLM API 集成

团队需要决定这两个 Layer 使用 Java(与 Control Layer + Data Layer 一致)还是 Python。

决策:

Reasoning & Decision Layer 和 Agent Runtime Layer 必须使用 Python 3.x + FastAPI,禁止使用 Spring Boot。

备选方案:

方案 A: Java + Spring Boot

  • 优点: 与 Control Layer + Data Layer 技术栈统一,团队 Java 经验丰富,JVM 运行时性能优秀
  • 缺点: ML/AI 生态远不如 Python;与 PyTorch、Transformers、LangChain 集成需要通过 JNI 或子进程调用,增加复杂度;AI 领域几乎所有新库和模型都优先提供 Python SDK
  • 未选择原因: AI/ML 是 Reasoning & Decision Layer + Agent Runtime Layer 的核心能力,选择 Java 意味着永远在"追赶"Python 生态,而不是"利用"它

方案 B: Python + Django

  • 优点: Django 是 Python 最成熟的 Web 框架,ORM 功能强大
  • 缺点: Django 是同步框架,异步支持(async views)是后加的,不够原生;Django 的 ORM 在 coomia-dip 中用不上(数据访问通过 Ontology 层);框架太重,很多功能用不到
  • 未选择原因: FastAPI 从设计之初就是异步的,完美匹配 AI/ML 工作负载的 I/O 密集特性;Pydantic 集成提供了原生的数据验证和序列化

方案 C: Python + Flask

  • 优点: 轻量灵活,学习曲线平缓
  • 缺点: 无内置异步支持(需要 Quart 或 ASGI 适配器);无内置数据验证;无自动 OpenAPI 文档生成
  • 未选择原因: FastAPI 在异步性能、类型安全和 API 文档方面全面优于 Flask

后果:

正面:

  • 直接访问 Python AI/ML 生态(PyTorch, Transformers, LangChain 等)
  • FastAPI 的异步原生支持完美匹配 LLM API 调用的高延迟特性
  • Pydantic v2 提供了运行时类型验证,与 Protobuf 消息格式互补
  • 招聘 AI/ML 工程师更容易——Python 是该领域的通用语言

负面:

  • 团队需要同时维护 Java 和 Python 两套技术栈
  • Python 运行时性能不如 JVM(对 CPU 密集任务有影响)
  • 依赖管理(pip/poetry)不如 Gradle 统一
  • 两种语言的代码风格和最佳实践不同,需要双份规范

#4.2 ADR-301: Gradle 优于 Maven 用于 Java 构建

状态: 已接受

日期: 2025-06-20

背景:

coomia-dip 的 Java 项目(Control Layer 和 Data Layer)需要选择构建工具。项目 CLAUDE.md 已将此列为技术红线:

Code
❌ Java 项目使用 Maven(必须用 Gradle)

需要理解这条红线背后的技术考量。

决策:

所有 Java 项目必须使用 Gradle 8.x 构建。

备选方案:

方案 A: Maven

  • 优点: 行业标准,约定优于配置,大多数 Java 开发者熟悉,IDE 支持完善
  • 缺点: XML 配置冗长,自定义任务需要编写插件;增量构建能力弱——每次构建几乎都是全量;多模块项目构建速度慢(比 Gradle 慢 2-3 倍);不灵活,复杂构建需求需要大量插件配置
  • 未选择原因: coomia-dip 的 Control Layer 和 Data Layer 都是多模块项目(10+ 子模块),Maven 的全量构建模式在日常开发中浪费大量时间

方案 B: Bazel

  • 优点: Google 开源,极致的增量构建和缓存,支持多语言(Java + Python 统一构建)
  • 缺点: 学习曲线极陡,配置复杂度远超 Gradle;Java 生态集成不如 Gradle(很多库没有 Bazel 构建规则);团队无 Bazel 经验
  • 未选择原因: Bazel 的优势在超大规模单体仓库中才能体现,coomia-dip 的项目规模使用 Gradle 已经足够

后果:

正面:

  • 增量构建使日常开发的构建时间从分钟级降到秒级
  • Kotlin DSL 的 build.gradle.kts 提供了类型安全的构建配置
  • Gradle 对 Protobuf 代码生成的插件支持完善(protobuf-gradle-plugin
  • 与 Spring Boot 和 Quarkus 的 Gradle 插件集成良好

负面:

  • 部分团队成员需要从 Maven 过渡到 Gradle
  • Gradle 的灵活性有时导致"一千种方式做同一件事"
  • Gradle Wrapper 版本管理需要额外关注

#5. 核心 ADR 详解:数据存储

#5.1 ADR-101: Apache Doris 作为 OLAP 引擎

状态: 已接受

日期: 2025-07-10

背景:

coomia-dip 需要一个 OLAP 引擎来支持:

  • 大规模数据分析查询
  • 物化视图(ComputationCoordinator 的 MATERIALIZED 模式)
  • 实时数据写入和近实时查询
  • SQL 兼容性(降低学习成本)

决策:

使用 Apache Doris 作为平台的主 OLAP 引擎。

备选方案:

方案 A: ClickHouse

  • 优点: 单表查询性能极佳,列式存储压缩率高,社区活跃
  • 缺点: 多表 JOIN 性能较差(coomia-dip 的关系查询场景频繁);物化视图功能有限;分布式事务支持弱;实时更新(UPSERT)需要 ReplacingMergeTree 引擎,存在数据短暂不一致窗口
  • 未选择原因: coomia-dip 的 Ontology 查询经常涉及对象关系的多表 JOIN,这是 ClickHouse 的短板

方案 B: Apache Druid

  • 优点: 实时摄入能力强,时序数据查询优秀
  • 缺点: SQL 支持不完整;不支持标准 UPDATE/DELETE;运维复杂度高(多种节点类型);物化视图能力弱
  • 未选择原因: coomia-dip 不是纯粹的时序分析场景,需要完整的 SQL 语义

方案 C: StarRocks

  • 优点: 与 Doris 架构类似,性能测试略优,物化视图功能强
  • 缺点: 商业公司主导,社区版功能受限;国内用户社区不如 Doris 活跃;长期发展方向受商业策略影响
  • 未选择原因: Doris 作为 Apache 顶级项目,社区治理更开放,长期可持续性更有保障

后果:

正面:

  • MySQL 兼容的 SQL 语法降低了团队学习成本
  • 物化视图功能直接支持 ComputationCoordinator 的 MATERIALIZED 模式
  • 实时写入 + 近实时查询满足大部分派生属性计算需求
  • Apache 基金会项目保证了开源可持续性

负面:

  • Doris 的生态(连接器、工具)不如 ClickHouse 丰富
  • 极端性能场景下不如 ClickHouse(但 coomia-dip 的查询模式不属于极端场景)
  • 需要关注 Doris 版本升级的兼容性

#6. 核心 ADR 详解:架构模式

#6.1 ADR-601: 强制 Ontology 路由

状态: 已接受

日期: 2025-06-25

背景:

项目 CLAUDE.md 的技术红线:

Code
❌ 绕过 Ontology 直接查库

这条红线要求所有数据访问必须通过 OntologyRuntimeService,即使这意味着额外的 gRPC 调用开销(2-5ms)。需要记录这个决策的完整上下文。

决策:

所有服务的数据读写必须通过 OntologyRuntimeService 的 gRPC 接口完成,禁止任何服务直连底层数据库。

理由(详见 S2-04 Ontology 内核专题):

  1. 统一权限检查:Ontology 层在每次操作中执行权限验证,直连数据库会绕过权限体系
  2. Schema 验证:Ontology 层保证所有写入符合 ObjectType 定义的约束
  3. 审计追踪:每次操作自动记录审计日志,直连数据库会产生"不可追踪"的数据变更
  4. 事件发布:数据变更自动触发 CDC 事件,直连数据库会导致派生属性无法级联更新

被否决的替代方案:

"允许只读直连"——有人提议允许只读场景直连数据库以提高查询性能。被否决的原因:

  • 只读查询仍然需要权限检查
  • 只读查询也需要审计记录
  • "只读直连"一旦开口子,很快会演变为"写入也直连"
  • 2-5ms 的 Ontology 开销对大多数场景可接受

#7. ADR 生命周期管理

#7.1 ADR 状态流转

Code
提议 (Proposed)
  │
  ├── 团队讨论 & 技术评审
  │
  ├── 接受 (Accepted)
  │       │
  │       ├── 环境变化 / 新需求
  │       │
  │       └── 取代 (Superseded by ADR-XXX)
  │               │
  │               └── 新 ADR 引用旧 ADR
  │
  └── 拒绝 (Rejected)
          │
          └── 记录拒绝原因(同样有价值)

#7.2 何时创建 ADR

不是每个技术决定都需要 ADR。coomia-dip 的判断标准:

需要 ADR不需要 ADR
选择数据库或消息队列选择日志格式
选择通信协议选择代码缩进风格
选择编程语言选择变量命名约定
确定安全架构模式选择具体的加密算法
改变系统边界重构内部实现细节

简单规则:如果这个决策在 6 个月后有人会问"为什么",就写一个 ADR。

#7.3 ADR 更新策略

ADR 一旦被接受,正文内容不应修改(它记录的是"当时"的决策上下文)。如果需要变更,创建新 ADR:

Markdown
# ADR-102: 从 Doris 迁移到 Doris + Iceberg 混合架构

## 状态
已接受(取代 ADR-101 中的"Doris 作为唯一 OLAP 引擎"部分)

## 背景
ADR-101 选择 Doris 作为唯一 OLAP 引擎。经过 6 个月的运行,
发现冷数据存储在 Doris 中成本过高。需要引入 Iceberg 作为
冷数据存储层...

#8. ADR 与项目红线的关系

#8.1 红线 = ADR 的强制执行

coomia-dip CLAUDE.md 中的每条技术红线都对应一个或多个 ADR:

技术红线对应 ADR核心理由
禁止 REST 内部通信ADR-001性能 + 跨语言类型安全
Reasoning & Decision Layer + Agent Runtime Layer 禁止 Spring BootADR-201AI/ML 生态兼容
禁止 MavenADR-301增量构建效率
禁止绕过 OntologyADR-601权限 + 审计 + 事件
禁止 as anyADR-702类型安全
禁止空 catch 块ADR-401可调试性

#8.2 红线的例外流程

如果开发者确实遇到需要突破红线的特殊场景,必须通过以下流程:

Code
1. 提交"红线例外申请 ADR"
   ├─ 说明为什么必须突破红线
   ├─ 说明影响范围
   └─ 提出缓解措施

2. 架构评审
   ├─ 至少 2 名 Senior 评审
   └─ 记录评审结论

3. 如批准
   ├─ 在 ADR 中记录"限定范围"的例外
   ├─ 设置检查点(例外是否仍然必要)
   └─ 通知相关 Layer 负责人

#9. ADR 的团队协作价值

#9.1 新成员上手

对于新加入 coomia-dip 的开发者,ADR 是最有效的上手资料之一。通过阅读核心 ADR,新成员可以在 2-3 小时内理解:

  • 为什么使用这些技术而不是其他技术
  • 历史上考虑过哪些备选方案
  • 每个关键决策的权衡和妥协
  • 哪些约束是可以挑战的,哪些是不可动摇的

#9.2 跨团队对齐

在 coomia-dip 的多 Layer 架构中,不同团队负责不同的 Layer。ADR 确保所有团队在关键技术决策上保持一致:

Code
Control Layer 团队: "我们想用 REST 暴露一个新接口"
    → 查看 ADR-001 → 理解为什么必须用 gRPC
    → 如果有特殊需求 → 提交例外 ADR

Reasoning & Decision Layer 团队: "我们想引入 Go 重写性能关键路径"
    → 查看 ADR-201 → 理解为什么选择 Python
    → 如果性能需求合理 → 提交新 ADR 评估 Go 引入的可行性

#9.3 技术债务管理

ADR 中记录的"负面后果"和"风险"是技术债务的早期预警系统。团队可以定期回顾 ADR 的预测:

Code
ADR-001 的预测风险: "调试困难影响开发效率"
    → 6 个月后回顾 → 确实出现了调试痛点
    → 已通过引入 grpcurl + gRPC 反射缓解
    → 记录在 ADR-001 的"回顾"部分

#10. ADR 反模式

#10.1 常见反模式

反模式描述后果
事后补写决策已执行数月后才写 ADR上下文丢失,备选方案回忆不全
过于详细ADR 写成 20 页设计文档没人愿意读和写
缺少备选方案只记录"选了什么"不说"还考虑了什么"未来开发者无法理解决策上下文
决策不可执行"我们应该考虑性能"不是具体的、可执行的决策
永不回顾ADR 写完就束之高阁决策可能已过时但无人知道
偷偷修改直接修改已接受 ADR 的正文破坏决策历史链路

#10.2 好的 ADR 的标准

一个高质量的 ADR 应该能让 6 个月后的读者在 5 分钟内理解:

  1. 当时面临什么问题(背景)
  2. 做了什么决定(决策——一句话概括)
  3. 为什么不选其他方案(备选方案——最有价值的部分)
  4. 需要承受什么代价(后果——诚实面对负面影响)

#11. ADR 工具链

#11.1 存储与组织

coomia-dip 将 ADR 作为代码仓库的一部分:

Code
docs/
└── adr/
    ├── README.md                    ← ADR 索引
    ├── templates/
    │   └── adr-template.md          ← 标准模板
    ├── 001-grpc-over-rest.md
    ├── 101-doris-as-olap.md
    ├── 201-python-for-intelligence.md
    ├── 301-gradle-over-maven.md
    ├── 401-testing-pyramid.md
    ├── 501-docker-compose-deployment.md
    ├── 601-ontology-routing.md
    └── 701-python-sdk-first.md

#11.2 ADR 与 Git 的集成

ADR 变更遵循与代码相同的版本控制流程:

  • ADR 的创建和修改通过 PR 提交
  • PR 需要至少 2 名 Reviewer 审批
  • 合并后通过 Commit Message 记录(使用 增加:更新: 前缀)
Code
增加: ADR-102 Doris + Iceberg 混合存储架构决策

#11.3 自动化索引

CI 流水线中包含一个自动化脚本,在每次 ADR 变更时重新生成 README.md 索引:

Python
# scripts/generate_adr_index.py
def generate_index(adr_dir: str) -> str:
    """扫描 ADR 目录,生成 Markdown 索引"""
    adrs = []
    for path in sorted(Path(adr_dir).glob("*.md")):
        if path.name in ("README.md", "adr-template.md"):
            continue
        title = extract_title(path)
        status = extract_status(path)
        date = extract_date(path)
        adrs.append(f"| [{path.stem}]({path.name}) | {title} | {status} | {date} |")

    header = "| ADR | 标题 | 状态 | 日期 |\n|-----|------|------|------|\n"
    return header + "\n".join(adrs)

#12. ADR 与架构演进

#12.1 决策链路追踪

ADR 之间通过引用关系形成"决策链路":

Code
ADR-001 (gRPC 内部通信)
    │
    ├── ADR-002 (Protobuf Schema 管理)
    │       └── ADR-003 (Proto 文件单仓管理)
    │
    └── ADR-004 (gRPC 流式传输用于事件推送)
            └── ADR-005 (Kafka 作为事件骨干 → 替代 gRPC 流)

ADR-101 (Doris 作为 OLAP)
    │
    └── ADR-102 (Doris + Iceberg 混合架构 → 取代 ADR-101 的部分决策)

#12.2 架构演进的可追溯性

通过 ADR 链路,可以清楚地看到架构是如何一步步演进的:

Code
2025-06: ADR-001 → 选择 gRPC 内部通信
2025-07: ADR-004 → 考虑用 gRPC 流做事件推送
2025-08: ADR-005 → 发现 gRPC 流不适合大规模事件,改用 Kafka
2025-09: ADR-006 → 基于 Kafka 建设 7 种事件角色(见 S2-06)

这个演进链路回答了"为什么现在用 Kafka 做事件推送而不是 gRPC 流"——因为 ADR-004 尝试过,ADR-005 记录了为什么放弃。

#13. 与 Palantir Foundry 的对比

维度Palantir Foundrycoomia-dip
决策记录内部技术备忘录 (闭源)ADR 公开文档 (代码仓库)
决策追踪Confluence + JIRAGit 版本控制 + Markdown
技术红线内部规范文档CLAUDE.md + ADR
新人上手导师制 + 内部培训ADR 自助阅读 + 导师制
决策更新文档更新通知PR 审批 + Git 历史
架构治理架构评审委员会ADR 提交 + 同行评审

coomia-dip 作为开源项目,ADR 的透明性是一个核心优势。任何贡献者都可以阅读完整的决策历史,理解"为什么",而不只是看到"是什么"。

#14. 实践建议

#14.1 从第一天开始写 ADR

不要等到项目"稳定"了才开始写 ADR。最有价值的决策通常发生在项目早期,而早期的上下文最容易被遗忘。

#14.2 保持轻量

一个 ADR 不应超过 2 页。如果发现写得太长,可能是把设计文档和决策记录混在一起了。ADR 只记录"决策",设计细节放在其他文档中。

#14.3 备选方案是最有价值的部分

花更多时间写"为什么不选 X"而不是"为什么选 Y"。因为"选了 Y"是代码中可见的事实,但"为什么不选 X"是只存在于决策者脑中的隐性知识。

#14.4 定期回顾

每个季度花 1-2 小时回顾现有 ADR:

  • 哪些决策的负面后果已经显现?
  • 哪些备选方案现在变得更有吸引力了?
  • 哪些 ADR 需要创建后续 ADR 来修正?

#Key Takeaways

  1. ADR 记录的核心不是"选了什么"而是"为什么不选其他"。 代码本身就是"选了什么"的最佳文档,但"为什么"只存在于决策者的脑中。当决策者离开团队后,这些关键上下文就永远丢失了。coomia-dip 通过 ADR 系统将隐性知识转化为显性文档,确保每个技术红线都有可追溯的决策依据。

  2. ADR 是"活文档"而非"历史归档"——旧决策不删除,而是被新决策取代。 这种链式结构保持了完整的决策演进历史。当有人问"为什么从 gRPC 流改成 Kafka 做事件推送",ADR 链路清楚地记录了尝试 → 问题 → 变更的完整过程。

  3. 技术红线必须有 ADR 支撑,否则就是"独裁"而非"治理"。 coomia-dip 的 CLAUDE.md 中每条技术红线都对应一个 ADR,开发者可以阅读 ADR 理解"为什么有这条红线"。如果有合理理由需要突破红线,可以提交例外 ADR 经团队评审。这种机制平衡了架构一致性和灵活性。

系列回顾: S2 架构全景系列到此完结。从第 1 篇的八 Layer 架构到第 15 篇的架构决策记录,我们完整地呈现了 coomia-dip 的架构设计思路、技术选型理由和工程实践方法。希望这些文章能帮助读者不仅理解"coomia-dip 是什么",更理解"coomia-dip 为什么是这样"。

Tags: #adr #architecture-decision-record #technical-governance #red-line #grpc #gradle #python #doris #ontology #decision-tracking #coomia-dip #智策平台