Skip to content

08 · 架构决策记录(ADR)与演进

上一章你学会了从 0 设计一个系统。但系统设计完不是终点——它会随业务长大、被后人接手、在你早忘了「当初为什么」的时候继续运行。这一章讲怎么让架构活得久、长得好


开场:最先丢失的,永远是「为什么」

想象一个场景。你接手一个三年前别人设计的系统,翻开代码,看到一个奇怪的设计:订单数据被同时写进了两个不同的存储,中间还有套对账逻辑。你的第一反应是:「这不脱裤子放屁吗?写一个不就完了?」于是你大笔一挥,删掉一个、合并逻辑——

三周后线上炸了。原来当年之所以这么设计,是因为有个监管要求订单流水必须落进一个不可篡改的存储,而主库要支持高频改单,两个诉求无法在一个存储上同时满足。这个理由,代码里一个字都没写,当年拍板的人也早就离职了。

这就是架构最致命的信息流失:代码和图能告诉你系统「是什么」,但几乎永远讲不清「为什么这么选、当初放弃了什么」。 而恰恰是后者,才是接手的人最需要、也最容易丢失的东西。

口头说过的「咱们这么定是因为……」,会在三次会议、两次离职、一年时间之后,蒸发得一干二净。等需要它的时候,只剩下一个看起来莫名其妙的设计,和一群不敢动它的人。

这一章给的解药很简单,简单到很多人不屑于做——把重要的架构决策,用一页纸记下来。 这页纸叫 ADR。


一、ADR:给架构决策建一本「为什么」的账

ADR = Architecture Decision Record,架构决策记录。 它是一份轻量文档,每做一个重要架构决策,就写一份,记下这个决策的来龙去脉。

它的精髓全在「轻量」二字:

  • 一个决策一份,通常一页纸,几分钟能读完。
  • 追加,不修改:决策变了就写新的一份,把旧的标记为「被取代」——保留历史,而不是抹掉历史。因为「我们曾经这么想、后来为什么改了」本身就是宝贵信息。
  • 和代码放在一起(比如仓库里一个 docs/adr/ 目录),让它随代码一起被版本管理、被搜索、被 review。

一个可以直接抄走的 ADR 模板

┌──────────────────────────────────────────────────────────┐
│  ADR-007:订单流水采用「主库 + 不可篡改日志」双写          │
├──────────────────────────────────────────────────────────┤
│                                                            │
│  状态:已采纳                                              │
│       (草稿 / 已采纳 / 已废弃 / 被 ADR-015 取代)          │
│                                                            │
│  日期:2026-05-23     决策者:架构组 + 合规                │
│                                                            │
│  ── 背景 / 上下文 ───────────────────────────────────     │
│  监管要求订单流水必须落入「写后不可改」的存储以备审计;     │
│  但业务又要求订单可被高频修改(改地址、改数量)。           │
│  单一存储无法同时满足「可改」与「不可篡改」。              │
│                                                            │
│  ── 决策 ───────────────────────────────────────────     │
│  主库存可变订单状态,服务高频读写;                        │
│  同时把每次变更追加写入一份不可篡改日志,作为审计依据;     │
│  以日志为准做定期对账。                                    │
│                                                            │
│  ── 考虑过的其它选项 ───────────────────────────────      │
│  A. 只用主库 + 软删除标记 → 否决:软删除仍可被改,过不了审计 │
│  B. 只用不可篡改存储 → 否决:无法支持改单,业务不可接受     │
│  C. 双写(本方案) → 采纳                                  │
│                                                            │
│  ── 取舍与后果 ─────────────────────────────────────     │
│  + 同时满足了合规与业务两个硬约束                          │
│  − 引入双写,需要对账逻辑兜底两边不一致(已知复杂度)       │
│  − 后人会觉得「多此一举」——本 ADR 就是写给你看的,别删!   │
│                                                            │
└──────────────────────────────────────────────────────────┘

模板就六块,记牢这六个标题就够了:

字段写什么为什么不能省
标题一句话说清这个决策是什么方便日后检索
状态草稿 / 已采纳 / 已废弃 / 被某 ADR 取代让读者知道这条还算不算数
背景 / 上下文当时面临什么问题、什么约束后人最缺的就是「当时的处境」
决策我们最终决定怎么做「是什么」——这部分代码里也能看到
考虑过的其它选项还想过哪些方案,为什么没选「放弃了什么」是 ADR 独有的价值
取舍与后果这个选择带来什么好处、什么代价、什么已知债务让后人清楚地继承「这是有意的取舍」

注意上一章的呼应:你在 07 的步骤 ⑧ 里,被反复要求说出「我选了 A、放弃了 B、因为……」和「未决问题」。那些话,逐字逐句就是一份 ADR 的『决策 + 其它选项 + 取舍』。 ADR 不是额外的负担,它只是让你把本来就该想清楚的东西,落在纸上别让它跑了。


二、强观点:记「为什么」比记「是什么」重要一百倍

这是这一章、甚至整个仓库最想让你记住的一条原则,值得单独拎出来反复说:

代码、架构图、API 文档,记录的全是「是什么」——系统现在长这样、有这些模块、这样调用。这些东西,只要你愿意,随时能从系统本身「读」出来。

但「为什么是这样、当初放弃了什么、在拿什么换什么」——这是『读』不出来的。它只活在做决定那个人的脑子里,不写下来,就随风而逝。

为什么「为什么」这么金贵?三个理由:

  1. 「是什么」会自我证明,「为什么」不会。 看代码就知道系统是什么样;但代码永远不会告诉你「我们本来想用更简单的方案 B,是因为某个约束才忍痛上了复杂的方案 C」。
  2. 没有「为什么」,后人只能在两种错误里二选一:要么不敢动(「这设计看着怪,但谁知道动了会不会出事」,于是系统僵化),要么乱动(像开场那个删双写的例子,直接踩雷)。有了「为什么」,后人才能安全地判断「这条约束还在不在,这个决策还成不成立」。
  3. 「为什么」是可迁移的智慧,「是什么」只是一次性的结果。 一份好 ADR 里「我们为了 A 牺牲了 B」的推理,换个项目、换个系统,后人还能复用那套权衡思路——这正是本仓库一以贯之的信念。

💡 一句话立此原则:好的文档不解释「代码做了什么」(代码自己会说),好的文档解释「代码为什么这么做」(代码永远不会说)。 把记录的力气,花在那些一旦丢失就再也找不回来的东西上。

这也正是 根 README 的三条阅读原则 里第一条的延伸:「先问『为什么』,再看『怎么做』。看不到取舍,就等于没看懂。」——ADR,就是把这条原则从「读」变成「写」。


三、演进式架构:别想一次设计到位,要留好「接缝」

07 反复讲「架构是迭代出来的」。但**「能迭代」本身,是要设计的**——一个糟糕的架构,改一点就牵一发动全身,根本迭代不动。

演进式架构(Evolutionary Architecture) 的核心思想是:

既然你注定无法一次设计对,那就把架构设计成「容易改对」的样子。 重点不是「现在完美」,而是「将来能低成本地替换某一块」。

怎么做到「容易改对」?答案是留好「接缝」(seam)——也就是清晰的模块边界和接口。一个有好接缝的系统,长这样:

   没有接缝(一团泥):                 留好接缝(模块化):

   ┌─────────────────────┐           ┌────────┐  接口  ┌────────┐
   │  所有逻辑揉成一坨     │           │ 模块 A  │◀─────▶│ 模块 B  │
   │  支付、库存、通知     │           └────────┘        └───┬────┘
   │  互相直接调来调去     │                                 │ 接口
   │  改一处,处处地震     │           ┌────────┐  接口  ┌──▼─────┐
   └─────────────────────┘           │ 模块 D  │◀─────▶│ 模块 C  │
                                      └────────┘        └────────┘
   想换掉「通知」?                    想换掉模块 C?
   → 不可能,它和谁都缠在一起          → 拔掉它、换一个,只要接口不变,
                                         其它模块毫无感觉

接缝的价值,在于把「将来的不确定」隔离开。 举几个上一章短链服务的例子:

  • 你把「短码生成」做成一个有清晰接口的独立模块。第一版用「预批发号段」,将来如果想换成别的生成策略,只换这一块,跳转服务和存储毫不知情
  • 你把「缓存」藏在跳转服务的接口背后。第一版用进程内缓存,涨上去了换成 CDN——对调用方是透明的

这正是每个模板「第 12 节 · 演进路线」在传递的智慧:AI 对话产品的演进路线 里,MVP 阶段直接调外部模型 API,成长期才换成自建推理 + 连续批处理——之所以换得动,正因为「调用模型」这件事一开始就被收在一个清晰的边界后面。好的接缝,让演进从『重写』变成『替换』。

💡 设计时多问一句:「这一块,将来最可能被换掉吗?」 最可能变的地方,就要用最干净的接口把它「包」起来,给它留好接缝。这是用「现在多想一点」换「将来少痛一片」。


四、技术债:它不全是坏事,关键是「记账」

「技术债」这个词常被当成纯贬义——好像欠了债就是干了坏事。这是个误解。

技术债的真正含义,借自金融:为了「现在更快地拿到价值」,而有意识地选了一个将来需要偿还的权宜方案。 就像借钱办事——借钱本身不是错,关键是你知不知道自己借了、打不打算还。

技术债分两种,要分清:

   ┌───────────────────────────┬───────────────────────────┐
   │   有意识的债(健康)        │   无意识的债(危险)        │
   ├───────────────────────────┼───────────────────────────┤
   │ 「为了赶上发布,这版先用    │ 「我也不知道为什么这里这么   │
   │   最简单的方案,记 TODO,    │   写,反正能跑」             │
   │   下季度重构」              │                            │
   │                            │                            │
   │ → 是理性的商业权衡          │ → 是失控,你甚至不知道欠了债 │
   │ → 写进 ADR / backlog,排期还 │ → 哪天突然爆雷,完全没准备    │
   └───────────────────────────┴───────────────────────────┘

对一个 MVP 来说,故意欠技术债往往是正确的——07 里短链服务第一版「单存储 + 单机发号」就是一笔债,但它换来了「快速上线、验证需求」,完全划算。错的不是欠债,而是:

  • 不知道自己欠了债(无意识的债,最危险);
  • 欠了债不记录(还是会忘「为什么」,回到本章开篇那个坑);
  • 永远只借不还(债越滚越大,直到某天系统改不动了)。

处理技术债的纪律就三条:① 有意识地借(明确这是权宜之计);② 把它记下来(一笔技术债,就是一条该写的 ADR——背景是「为什么暂时这么凑合」);③ 安排偿还时机(挂进 backlog,定个「当 X 发生时就还」的触发条件,而不是「有空再说」)。

把技术债当成「记在账上、按计划偿还的负债」来管理,而不是「藏在地毯下、假装不存在的脏东西」——这是成熟团队和草台班子的分水岭。


五、康威定律:你的架构,会长得像你的组织

聊架构演进,绕不开一条「定律」。它不是技术规律,而是社会学观察,却深刻影响每一个系统的最终形态:

康威定律(Conway's Law):系统的架构,会不可避免地长得像设计它的那个组织的沟通结构。

翻成人话:两个模块之间的接口,长得像这两个模块背后那两拨人之间的沟通方式。 如果两个团队天天开会、坐在一起,他们做出来的两个模块大概率紧密耦合;如果两个团队分属不同部门、只能靠邮件交流,他们的模块之间就会自然形成清晰(甚至僵硬)的边界。

   组织长这样:                           系统就会长成这样:

   ┌─────────┐   ┌─────────┐            ┌─────────┐   ┌─────────┐
   │ 支付团队  │   │ 物流团队  │   ───▶    │ 支付服务  │   │ 物流服务  │
   │ (各自独立)│   │ (各自独立)│            │ (独立部署)│   │ (独立部署)│
   └─────────┘   └─────────┘            └────┬────┘   └────┬────┘
        几乎不沟通,各管各的                    └─ 接口清晰、松耦合 ─┘

   ┌───────────────────────┐            ┌───────────────────────┐
   │   一个大团队啥都管        │   ───▶     │   一个大单体,啥都揉一起  │
   └───────────────────────┘            └───────────────────────┘

康威定律对架构演进有两条极其重要的启示:

  1. 拆服务之前,先看团队结构。 你想把单体拆成微服务(04 讲过微服务),但如果团队还是一锅粥、谁都管所有事,那拆出来的「微服务」之间照样紧耦合、改一个动一片——架构边界和团队边界对不齐,拆了也是白拆。 想要松耦合的服务,先有边界清晰、能独立负责的团队。
  2. 反过来用它(逆康威操作):想要什么样的架构,就先组织成什么样的团队。 你希望系统由几个独立演进的服务组成?那就先按这些服务把人分成几个能独立决策的小队,架构会自然朝你要的方向长。组织设计,本身就是一种架构设计。

💡 康威定律的本质提醒:架构问题,常常是组织问题伪装的。 当你发现两个模块怎么解耦都解不干净,先别急着改代码——去看看是不是背后那两拨人本就分不开。很多「架构难题」,真正的解法在组织结构里,不在技术里。


六、什么时候该重构 / 该升级架构?(用判断,不用感觉)

系统在长大,你迟早面临这个问题:现在这套架构,该不该动了? 新手常凭两种糟糕的依据做决定:

  • 凭感觉:「这代码看着真丑,重构吧」——丑不是升级架构的理由,不影响任何质量属性的丑,可以先忍
  • 跟风:「大厂都上微服务/中台/某新架构了,我们也上」——别人的瓶颈不是你的瓶颈,照搬大厂成熟期的架构套自己的成长期,是头号过度设计

那靠什么判断?靠前六章学的两把尺子:瓶颈和质量属性。

   该不该升级架构?——拿这两把尺子量,而不是拍脑袋:

   ┌────────────────────────────────────────────────────────┐
   │  尺子一:瓶颈(来自 06 + 07 步骤⑦)                      │
   │   现在,某个质量属性是不是已经被架构卡住了?             │
   │   • 数据库读到冒烟、加再多缓存也压不住了?               │
   │   • 一个模块改动总是连累一片、发布越来越慢?             │
   │   → 真实的、量出来的瓶颈,才是升级的信号                │
   ├────────────────────────────────────────────────────────┤
   │  尺子二:质量属性的变化(来自 06)                       │
   │   业务对「要多好」的要求,是不是上了一个台阶?           │
   │   • 可用性要求从 99% 提到 99.99%?                       │
   │   • 用户量/数据量进入了下一个量级(07 估算说的「100倍」)?│
   │   → 质量目标变了,旧架构撑不住了,才升级                │
   └────────────────────────────────────────────────────────┘

把判断流程固化成一句话:

不是「这架构旧了/丑了」就升级,而是「某个我真正在乎的质量属性,被当前架构卡住了,且这个卡点是真实存在(量出来)的瓶颈」才升级。 升级架构是有巨大成本和风险的动作,它必须是为了换取某个具体的、当下需要的质量属性——这正是 06 质量属性与取舍 教你的判断方式。

而且,每一次「决定升级架构」本身,就是一个该写 ADR 的重大决策:背景(什么瓶颈逼我们动)、决策(升成什么)、其它选项(还能怎么扛)、取舍(为这次升级我们付出什么)。——你看,本章所有的工具,最后都串回了 ADR。


本章小结

  • 最先丢失的永远是「为什么」:代码和图能说清系统「是什么」,但讲不清「为什么这么选、放弃了什么」——而后者才是后人最需要、最易蒸发的东西。
  • ADR(架构决策记录) 是解药:一份轻量、追加不修改、和代码放在一起的文档,记下每个重要决策。模板就六块:标题、状态、背景、决策、考虑过的其它选项、取舍与后果。
  • 强观点:记「为什么」比记「是什么」重要一百倍。 把记录的力气,花在那些一旦丢失就再也找不回来的东西上。
  • 演进式架构:别想一次设计到位,而要把系统设计成「容易改对」的样子——在最可能变的地方留好清晰的接缝(模块边界/接口),让演进从「重写」变成「替换」。
  • 技术债不全是坏事:它是有意识的权宜之计。纪律是「有意识地借、记下来、安排偿还时机」;危险的是无意识的、不记录的、只借不还的债。
  • 康威定律:架构会长得像组织的沟通结构。拆服务前先看团队边界;也可反向用它——想要什么架构,先组织成什么团队。架构难题常是组织难题的伪装。
  • 何时升级架构,靠判断不靠感觉:不是「旧了/丑了/别人上了」就升级,而是「某个真正在乎的质量属性被真实瓶颈卡住了」才升级——用 06 的尺子量,别拍脑袋。

📌 真实案例:ADR 的起源

本章讲的 ADR,来自 Michael Nygard 2011 年的博文 《Documenting Architecture Decisions》——他提出用一个个轻量小文件,记录每个决策的背景 / 决定 / 状态 / 后果。这套格式后来成了业界标准。

  • 📎 社区资源与各种模板 / 工具:adr.github.io
  • 本仓库每个模板的「关键决策与权衡」一节,本质就是一组写好的 ADR。

结语:成为一个「持续做出好判断、并把判断沉淀下来」的人

读到这里,整套教程就走完了。让我们回到最开始、回到这个仓库存在的理由(根 README):

写代码正在消失,而架构判断力,正变得前所未有地稀缺和值钱。

这八章,你学的从来不是某门语言、某个框架——它们都会过时,今年流行的明年就换。你学的是一种不会贬值的东西:

   会贬值的(AI 正在让它廉价):        不会贬值的(越来越稀缺):

   • 某个语法怎么写                     • 拿到模糊需求,问出对的问题
   • 某个框架的 API                     • 在取舍中做出有依据的选择
   • 某段样板代码                       • 看清系统会死在哪、该换什么
   • 一次性的实现                       • 把「为什么」沉淀成可复用的智慧
   ────────────────────────            ────────────────────────────
   → 交给 AI                            → 这,才是未来开发者的核心

而走完这最后两章,你应该对「优秀的架构师」有了一个比第一章更完整的画像。他不只是「能设计出好系统的人」(那是 07),更是一个持续地做出好的架构判断、并把每一个判断和它背后的理由都沉淀下来的人(那是 08)。

因为单次的好设计会随时间锈蚀,但**「不断判断 + 不断记录」这个循环**,会让你和你的系统一起,越来越强:

        ┌─────────────────────────────────────────┐
        │                                         │
        ▼                                         │
   做出一个架构判断 ──▶ 把「为什么」记成 ADR        │
   (用 01-07 的方法)         │                    │
                            ▼                    │
            业务长大 / 出现新瓶颈 ◀───────────────┘
            (用 06 的尺子重新判断,回到顶端)

            判断力在每一圈里复利增长

代码会变,框架会换,连「架构」这个词的时髦说法也会一茬接一茬。但在动手之前先想清楚系统该长什么样、并能讲清每个选择为什么——这种判断力,会在你整个职业生涯里持续增值。这,就是这个仓库想送给你的东西。


最后一个练习,然后就靠你自己了

把模板当 ADR 来读。 现在回到 ../templates/,挑任意一个系统,直奔它的第 8 节「关键架构决策与权衡」

你会发现:那一节的每一条,其实就是一份压缩版的 ADR——它有背景(面临的选择)、有决策(取向)、有放弃的选项、有取舍(代价)。试着把 AI 对话产品的「决策 1:流式还是一次性返回」 按本章那张六块模板,亲手补成一份完整的 ADR

做完这件事,你就同时拥有了这套教程的两样东西:像架构师一样『判断』(07),以及像架构师一样把判断『留下来』(08)。 剩下的,就是去真实世界里,一个系统接一个系统地练。


相关链接