跳到主内容

架构决策记录(ADR)总览

架构决策记录

架构决策记录(ADR)总览

架构决策记录(Architecture Decision Record,ADR)用于捕捉 EnerOS 项目中对架构有持续影响的关键决策。每条 ADR 记录决策的背景、动机、结论与后果,便于团队复盘与新成员理解设计脉络。

ADR 不是设计文档,也不是实现说明,而是回答”为什么在当时做出了这个选择”。当代码无法解释决策动机时,ADR 是最后的依据。EnerOS 是一套面向电力关键基础设施的操作系统,许多决策受合规、物理约束与长期演进影响,必须显式记录,否则随着人员更迭,决策原因会被湮没。

为什么需要 ADR

电力系统的软件开发具有以下特征,使得 ADR 尤为重要:

  • 长生命周期:电力系统投运后通常运行 10-30 年,决策影响远超个人在岗周期
  • 强合规约束:需同时满足 IEC 62443、NERC CIP、等保 2.0 等多套标准
  • 物理不可逆:错误的遥控命令可能造成设备损坏或大面积停电
  • 多方协作:电网公司、设备厂商、监管机构、研究机构均需理解系统设计
  • 技术演进快:AI、边缘计算、量子安全等新技术持续冲击既有架构

ADR 通过结构化记录决策上下文,让新加入的工程师在 30 分钟内理解”为什么内核要强制执行约束”、“为什么所有内部通信必须 mTLS”等关键问题,避免无意识推翻既定决策。

ADR 格式

EnerOS 采用 Michael Nygard 提出的轻量级 ADR 模板,并扩展为六节结构。每条 ADR 必须包含以下章节:

章节必填内容
状态(Status)提议 / 已接受 / 已废弃 / 已被取代
背景(Context)决策时面临的问题、约束与动机
决策(Decision)最终选择的方案及核心理由
后果(Consequences)带来的好处、代价与后续工作
备选方案(Alternatives)考虑过但未采用的方案及否决原因
参考(References)相关 ADR、标准、论文、Issue 链接

状态机

ADR 状态遵循以下流转规则:

提议 (Proposed)

   ├─ 评审通过 ──► 已接受 (Accepted)
   │                  │
   │                  ├─ 后续 ADR 取代 ──► 已被取代 (Superseded)
   │                  ├─ 严重问题暴露 ──► 已废弃 (Deprecated)
   │                  └─ 长期有效

   └─ 评审拒绝 ──► 已拒绝 (Rejected)

一旦状态变为”已接受”,原文件不再修改内容,只能被新的 ADR 取代。这是为了保证历史可追溯——任何决策的演进都通过新 ADR 显式记录。

ADR 列表

下表是 EnerOS 当前所有 ADR 的索引。编号从 0001 起,按时间递增,不复用。缺失的编号代表被拒绝或撤回的提议,仅保留编号占位以维持时序完整。

编号标题状态日期关键决策
0002Power-Native AgentOS 设计已接受2024-03电力领域知识下沉为内核一等公民
0007零信任与 mTLS 强制已接受2024-09所有内部服务通信强制 mTLS 双向认证
0010Agent 智能进阶路径已接受2025-03内核内置智能层,规则/模型/LLM 可插拔

注:编号 0001、0003-0006、0008-0009 的 ADR 涉及内部组件选型(如时序存储引擎、调度器实现、事件总线协议等),将在后续版本公开后逐步补全索引。

ADR 模板

新建 ADR 时,复制以下模板并按字段填写:

---
title: "ADR-NNNN 标题"
description: "一句话描述决策内容"
category: "架构决策记录"
order: NNNN
---

# ADR-NNNN 标题

- **状态(Status)**:提议 | 已接受 | 已废弃 | 已被取代
- **日期**:YYYY-MM
- **相关概念**:[关联文档链接](/docs/...)

## 背景(Context)

描述决策时面临的问题、约束、动机。包括:

- 触发该决策的具体场景或痛点
- 当时的技术约束(性能、合规、团队规模等)
- 不做该决策的代价

## 决策(Decision)

用 1-3 句话陈述最终选择。例如:

> 我们决定将 X 下沉为内核原生组件,由 Y 提供统一接口,强制 Z。

随后展开 3-5 条核心理由,每条理由配 1-2 句解释。

## 后果(Consequences)

分三类列出:

**好处**
- 好处 1
- 好处 2

**代价**
- 代价 1
- 代价 2

**后续工作**
- 待办 1
- 待办 2

## 备选方案(Alternatives)

列出考虑过但未采用的方案,每个方案包含:

### 方案 A:名称
- **描述**:方案概述
- **优点**:方案优点
- **否决原因**:为何未采用

## 参考(References)

- [相关 ADR](/docs/adr/NNNN-xxx)
- [标准/论文/Issue 链接]
- 相关代码 crate 名称

编写指南

何时写 ADR

满足以下任一条件即应撰写 ADR:

  • 引入或移除一个内核一等公民抽象(如拓扑、约束、设备模型)
  • 改变系统的安全边界或信任模型
  • 选择某项影响全局的第三方依赖或协议
  • 跨多个 crate 的接口变更
  • 决策可能被未来的工程师质疑或推翻
  • 涉及合规、性能、可用性的权衡取舍

何时不写 ADR

以下情况不需要写 ADR:

  • 单个 crate 内部实现细节(应写在代码注释或 crate 级 README)
  • Bug 修复(应写在 commit message 或 PR 描述)
  • 文档完善(应直接修改文档)
  • 临时实验性功能(应标记为 experimental,稳定后再考虑 ADR)

编写原则

  1. 一事一 ADR:一条决策对应一份文件,不要把多个决策合并
  2. 不可变:状态变为”已接受”后内容不再修改,只能被新 ADR 取代
  3. 可追溯:每个决策必须能回答”为什么不是另一个方案”
  4. 简洁:正文控制在 200-400 行,长篇分析放附录或独立文档
  5. 可验证:决策带来的后果应尽量给出可测量的指标(如延迟、吞吐)
  6. 关联:在前后相关的 ADR 之间建立显式引用

决策流程

EnerOS 的架构决策遵循以下流程,确保决策既严谨又高效:

   ┌──────────────┐
   │ 1. 识别决策点 │  ← 工程师或架构师发起
   └──────┬───────┘

   ┌──────────────┐
   │ 2. 起草 ADR   │  ← 使用模板,状态为"提议"
   └──────┬───────┘

   ┌──────────────┐
   │ 3. 公开评审   │  ← PR 形式,至少 2 名架构师审查
   └──────┬───────┘

   ┌──────────────┐
   │ 4. 评审结论   │  ← 通过 / 拒绝 / 需修改
   └──────┬───────┘

   ┌──────────────┐
   │ 5. 状态更新   │  ← 通过则"已接受",否则"已拒绝"
   └──────┬───────┘

   ┌──────────────┐
   │ 6. 落地实施   │  ← 代码实现 + 测试 + 文档同步
   └──────┬───────┘

   ┌──────────────┐
   │ 7. 复盘       │  ← 上线 3-6 个月后评估决策效果
   └──────────────┘

评审角色

角色职责人数
发起人起草 ADR,推动评审1
架构师评估技术合理性、与既有 ADR 一致性≥2
安全官评估安全与合规影响1(涉及安全时)
领域专家评估电力领域正确性1(涉及电力时)
实施者评估落地成本与工期1

评审标准

评审时重点关注以下维度:

  • 必要性:是否真的需要这个决策?维持现状的代价是什么?
  • 充分性:备选方案是否考虑周全?否决理由是否成立?
  • 一致性:与既有 ADR 是否冲突?是否引入新的矛盾?
  • 可逆性:决策是否可逆?如果被取代,迁移成本如何?
  • 可验证性:决策效果是否可测量?如何评估?

ADR 与其他文档的关系

EnerOS 的文档体系按”是什么 / 为什么 / 怎么做”三层组织,ADR 处于”为什么”层:

文档类型回答示例变更频率
概念文档是什么Power-Native First
架构文档怎么组织分层架构
ADR为什么这么决定本文档极低(一旦接受不可变)
能力文档能做什么Agent 智能进阶
操作指南怎么用首个 Agent
API 参考接口签名API Reference

ADR 是其他文档的”上游”:概念文档解释 ADR 引入的术语,架构文档实现 ADR 的决策,操作指南教用户使用 ADR 决定的能力。修改 ADR 时应同步检查下游文档是否需要更新。

编写约定

  • 编号从 0001 起,按时间递增,不复用
  • 一条决策对应一份文件,文件名格式 NNNN-kebab-case-title.md
  • 决策一旦被取代,原文件保留并标注 Status: 已被取代,新增 ADR 引用前置编号
  • ADR 仅记录”为什么这么决定”,不重复写实现细节
  • 日期精确到月份即可,无需到日
  • 正文使用中文,技术术语可保留英文(如 mTLS、SPIFFE、RBAC)
  • 代码示例必须完整可运行,不要用 // ... 省略关键逻辑
  • 表格必须包含完整的字段说明,不留空列

工具支持

EnerOS 仓库提供以下工具辅助 ADR 管理:

  • scripts/adr-new.sh:基于模板创建新 ADR,自动分配编号
  • scripts/adr-check.sh:检查所有 ADR 的格式与链接是否有效
  • scripts/adr-graph.sh:生成 ADR 之间的引用关系图

示例用法:

# 创建新 ADR
./scripts/adr-new.sh "timeseries-engine-selection"

# 检查所有 ADR
./scripts/adr-check.sh

# 生成关系图
./scripts/adr-graph.sh --output docs/adr/graph.svg

相关文档