架构决策记录(ADR)与技术方案(RFC)表达规范
架构与方案的本质是在冲突的约束中做权衡(Trade-offs)。没有完美的架构,只有适合当前阶段约束的妥协。
只写优点、不写代价的技术方案,是不诚实的欺骗。 一份深度的架构决策,必须清晰交代:为什么现有机制不可用、选它的代价是什么、放弃了哪些备选方案,以及在什么条件下本方案必须被推翻。
零、ADR / RFC 五步骨架(The Decision Skeleton)
动笔撰写任何技术提案、重构方案或架构决策前,按此骨架填空:
① 本质矛盾 第一性原理下钻 · 当前物理瓶颈是什么 · 不做该方案的年化代价 ② 决策结论 选了什么方案 · 核心架构图 · 数据流与契约约束 ③ 权衡矩阵 获得了什么 vs 付出了什么代价 · 引入的新复杂度由什么机制兜底 ④ 方案墓碑 考虑过的备选方案 B/C · 在当前什么事实下被否决(防止后人重复讨论) ⑤ 推翻条件 可证伪性 · 当什么指标突破阈值时,本架构必须被推翻重做
一、关键段落表达规范
1. 本质矛盾(Problem Definition)
- 先问第一性原理:问题本质是性能不够、模型能力不足、还是流程设计错误?
- 量化不做该方案的代价:
text
❌ “当前日志记录比较分散,排查问题不太方便,因此需要统一日志中心。” ✅ “当前 5 台服务器日志分散在各机本地,跨机事故定位需串行 SSH 查 5 次,平均 MTTR 为 42 分钟; 上月因日志分散导致的定位超时事故共 3 起,累计中断 114 分钟。”
2. 权衡矩阵与代价显式化(Trade-offs)
- 必须包含专门的小节:「我们付出了什么代价(Costs & Limitations)」。
- 交代三件事:
- 性能/延迟代价:增加了几毫秒网络延迟?增加了几倍磁盘读写?
- 心智/学习代价:团队理解新方案需要多长时间?API 是否破坏既有习惯?
- 运维兜底代价:新依赖挂了怎么办?是否有无状态降级预案?
3. 弃用方案墓碑区(Rejected Alternatives)
- 防止团队陷入“月经周期式重提旧方案”的内耗。
- 记录格式:
markdown
### 弃用方案:自建 Kafka 消息队列 - **为什么考虑过**:吞吐量极大,生态成熟。 - **为什么在当前阶段否决**: 1. 需至少 3 节点 ZooKeeper/KRaft 集群,每月闲置硬件成本增加 ¥1200+; 2. 当前系统峰值 QPS 仅为 140,PostgreSQL LISTEN/NOTIFY 或 Redis Stream 完全能承载; 3. 维护团队只有 1 人,缺乏 Kafka 集群调优与宕机恢复的专职人力。
4. 推翻与失效条件(Termination Conditions)
- 方案必须有自我消亡的判据(可证伪性)。
- 示例:
markdown
### 本决策推翻条件 当满足以下任一条件时,本方案视为已触及天花板,应推翻重选分布式方案: 1. 单表日增行数突破 500 万行,或历史数据归档后总表体积仍超过 100GB; 2. 跨机事务写延迟 p99 超过 200ms; 3. 团队规模扩展至 10 人以上,需要强隔离的多租户权限。
二、正反案例对比
❌ 假人八股方案(报喜不报忧)
关于引入 GraphQL 的技术提案
随着业务发展,传统 RESTful 接口存在过度获取和数据字段冗余的问题。GraphQL 作为业界主流方案,具有按需查询、类型安全、高性能等诸多优势,能够极大提升前后端协作效率,赋能业务快速迭代。经过调研,建议在下一阶段全面推广 GraphQL,替换现有 REST API。
✅ 工业级架构决策记录(ADR)
ADR-014:保持 RESTful JSON API,拒绝全面引入 GraphQL
一、决策背景
移动端与小程序界面改版频繁,存在同个实体在不同视图需不同字段的问题。部分团队提议引入 GraphQL。二、决策结论
维持 RESTful API + Sparse Fieldsets(通过?fields=id,name动态裁剪字段),拒绝引入 GraphQL 全量网关。三、权衡与代价分析
- 收益:避免引入 GraphQL 引擎带来的解析开销(实测单请求 CPU 消耗高 15%);保留现有基于 Cloudflare CDN 的 URL 级 HTTP 缓存机制;保持 PostgREST/Supabase 原生网关能力。
- 代价:对于复杂的嵌套深度图查询,客户端需要发起 2 次串行请求或依赖 BFF 层专门聚合。该代价通过在现有 Node 服务中增加专门的聚合路由解决。
四、墓碑方案(为什么否决 GraphQL)
- CDN 缓存穿透:GraphQL 默认走 POST 请求,天然破坏 Cloudflare 边缘缓存,将所有读请求压回源站;
- N+1 查询与 DoS 风险:需引入复杂的 DataLoader 和深度限制算法,团队当前缺乏应对恶意嵌套查询的防御经验;
- 工具链包袱:前端各仓库包体积需额外增加 ~40KB 的 Apollo Client 依赖。
五、推翻判据
当面向三方开放的 OpenAPI 实体关系嵌套超过 4 层且无法提前枚举视图模式时,方可重新评审 GraphQL 的局部接入。
三、📋 ADR / RFC 扣分清单(Deduction Rubric)
评审任何架构决策、技术方案或 RFC 前逐条核验,命中任何一项扣 25 分(满分 100,低于 75 分直接打回重写):
| 违规维度 | 扣分项(Anti-pattern) | 扣分 | 为什么致命 | 修正方案 |
|---|---|---|---|---|
| 代价隐瞒 | 通篇只讲优点,不写负面代价与引入的新复杂度 | -25 | 世界上没有免费的午餐,隐瞒代价意味着根本没做落地压力测试。 | 必须设立专门章节列出性能损耗、运维心智负担与单点故障风险。 |
| 墓碑缺失 | 没有记录被否决的备选方案与否决事实 | -25 | 评审人无法判断是“深思熟虑的最优选”还是“只知道这一个方案”。 | 明确写出考虑过哪些替代方案,因何种具体的现实约束而放弃。 |
| 推翻盲区 | 没有给出终止与推翻的指标条件 | -25 | 方案变成了永恒真理,技术债务会在业务膨胀后死死锁死系统。 | 设定具体的量化红线(如数据量、QPS、延迟阈值),达到即启动重构。 |
| 虚假量化 | 使用“大幅提升性能/极高扩展性/极其优雅”等主观形容词 | -25 | 毫无工程基准,空洞形容词无法作为事后验收的技术依据。 | 给出实测 Benchmark 数字、延迟压测毫秒数或架构吞吐量计算过程。 |


