大家好,我是 一步梅。做前端开发和写文档这么多年,我发现很多团队都有一个通病:代码里写满了「怎么做」(How),但没人知道当初「为什么这么做」(Why)。
接手老项目时,你一定见过类似的情况:
- 为什么全局状态管理既有 Redux 又有 Zustand?
- 为什么有的组件用 Tailwind CSS,有的又在用 CSS Modules?
- 为什么打包工具从 Webpack 换到了 Vite,却留了一堆没清理的 Polyfill?
去问老员工,老员工说:“当时好像是为了赶进度/为了解决某个线上 Bug,具体记不清了。”
为了不让后人(或者三个月后的你自己)对着代码抓狂,我们需要一套轻量、高效的机制来记录技术选型。这就是今天我们要聊的:架构决策记录(Architecture Decision Record,简称 ADR)与前端项目文档治理。
一、什么是 ADR?为什么前端特别需要它?
ADR(Architecture Decision Record) 是一种短小的文本文件(通常是 Markdown),用来记录软件项目中做出的重要架构决策、决策背景以及带来的影响。
前端技术生态迭代极快:框架升级、状态管理变迁、构建工具替换、微前端改造……每一个改动都可能影响整个仓库的研发体验。
ADR 的核心价值只有三句话:
- 记录上下文:当时面临什么业务和技术痛点?有哪些限制条件?
- 记录权衡(Trade-offs):为什么选方案 A 而不是方案 B?放弃了什么?
- 沉淀资产:新人入职看代码看不懂设计思路,看 ADR 列表 10 分钟就能理清架构演进史。
二、一份标准的前端 ADR 长什么样?
ADR 不需要写成长篇大论,通常包含五个核心部分:标题与状态、背景(Context)、决策(Decision)、后果(Consequences)、替代方案(Alternatives Considered)。
下面是一个真实的前端选型示例:
# 0003. 使用 TanStack Query 替代 Redux 管理服务端状态
- **状态**:已接受 (Accepted)
- **日期**:2024-03-15
- **决策人**:一步梅、前端基础组件小组
## 背景 (Context)
当前项目中,我们使用 Redux Toolkit + createAsyncThunk 来处理所有 API 请求和缓存。
随着业务复杂度增加,暴露了以下问题:
1. 样板代码过多:每个接口都需要定义 Slice、Thunk、Pending/Fulfilled/Rejected 状态。
2. 缓存失效与轮询逻辑复杂:在多标签页同步和数据失效刷新场景下,手写缓存逻辑极易出现 UI 与数据不一致的 Bug。
3. 团队成员经常把「服务端返回的临时数据」和「真正的全局客户端状态(如主题、当前登录用户信息)」混在同一个 Store 里。
## 决策 (Decision)
我们决定引入 `TanStack Query (React Query) v5` 来专门管理**服务端状态(Server State)**,原有的 `Redux Toolkit` 仅保留用于管理纯粹的**客户端全局状态(Client State)**。
执行原则:
1. 所有 GET 请求的列表、详情数据,必须封装为自定义 Hook 并使用 `useQuery`。
2. 涉及新增、修改、删除的操作,统一使用 `useMutation` 并触发相关的 Query Key 失效。
3. 禁止再将接口返回的业务实体数据手动同步到 Redux 中。
## 替代方案 (Alternatives Considered)
- **方案 A:继续沿用 Redux Toolkit + RTK Query**
- 未采纳原因:RTK Query 学习曲线稍陡,团队对 TanStack Query 的 Hooks API 更熟悉,且后者在 DevTools 调试和离线缓存方面更灵活。
- **方案 B:SWR**
- 未采纳原因:SWR 功能相对轻量,但在复杂的 Mutation 联动和分页缓存策略上,TanStack Query 提供的工具链更完善。
## 后果 (Consequences)
### 正面影响
- 减少约 40% 的数据请求相关样板代码。
- 自动获得开箱即用的窗口聚焦重新拉取、请求去重和后台静默更新能力。
- 职责清晰:Server State 归 TanStack Query,Client State 归 Redux。
### 负面影响 / 成本
- 引入了新的依赖包(打包体积增加约 13KB Gzip)。
- 存量代码需要分阶段迁移,在过渡期内项目中会同时存在两种数据获取方式(预计在 Q2 迭代中全部收敛)。
三、如何在前端项目中落地 ADR?
别把 ADR 搞成沉重的流程,只需遵循以下三个落地步骤:
1. 规范目录结构
ADR 必须和代码放在同一个 Git 仓库中(Docs as Code),推荐放在根目录的 docs/adr 下:
my-frontend-project/
├── docs/
│ └── adr/
│ ├── 0001-record-architecture-decisions.md
│ ├── 0002-adopt-pnpm-and-monorepo.md
│ └── 0003-use-tanstack-query-for-server-state.md
├── src/
├── package.json
└── README.md
2. 使用 CLI 工具辅助生成
你可以通过 adr-tools 或在 package.json 中配置简单的脚本来生成模版:
# 安装轻量管理工具(例如通过 npm)
npm install -g adr-log
# 或者在 package.json 里写一个极简脚本
# 运行 npm run adr:new -- "引入 Tailwind CSS" 自动生成编号和模版文件
3. 将 ADR 嵌入到 PR Code Review 流程中
- 何时需要写 ADR?
- 引入或废弃一个核心依赖库(如 UI 库、状态库、图表库)。
- 目录结构或工程规范重大调整(如引入 Monorepo、微前端改造)。
- 核心业务流程重构(如鉴权逻辑改动、大文件切片上传方案)。
- 流程规范:
涉及重大技术改造的 PR,必须包含对应新增的
docs/adr/xxxx.md。评审代码前,团队成员先 Review ADR,达成共识后再合入代码。
四、前端项目文档分层治理
ADR 解决的是「重大决策归档」问题,但一个健康的工程化项目,文档体系应该是有层次的。建议把前端文档划分为四层:
┌──────────────────────────────────────────────┐
│ 1. 入口层:README.md │ 👉 快速上手、本地启动、基础规范指引
├──────────────────────────────────────────────┤
│ 2. 决策层:ADR (docs/adr/*.md) │ 👉 技术选型历史、架构演进原因、权衡分析
├──────────────────────────────────────────────┤
│ 3. 指南层:Guides (docs/guides/*.md) │ 👉 状态管理规范、组件封装指南、CI/CD 流程
├──────────────────────────────────────────────┤
│ 4. 代码层:TS Types + TSDoc + Storybook │ 👉 组件 API、类型定义、交互 Demo(随代码走)
└──────────────────────────────────────────────┘
文档治理的两条铁律:
- 文档与代码同源:千万不要把核心开发文档扔到飞书/Notion/Confluence 里不管了。产品需求文档可以放云端,但技术架构和工程文档必须进 Git 仓库。代码变动时,文档和代码提在同一个 Commit 里,才能保证版本一致。
- 拒绝无效废话:函数签名已经用 TypeScript 说明清楚的,不要再在文档里机械重复参数类型;文档要写的是「业务约束」和「设计意图」。
总结
写文档不是为了应付检查,而是为了降低团队未来的沟通成本和试错成本。
用 ADR 记录一次决策只需要 15 分钟,但它能省下未来几个月里团队无数次「这个代码是谁写的、为什么这么写」的扯皮时间。
今天就可以在你的前端项目根目录建一个 docs/adr/ 文件夹,把你们上周刚讨论定的选型,写成第一篇 ADR 提交上去试试看。
License: CC BY-NC 4.0
Updated 14 hours ago
Was this article helpful? Give it a like.
0 comments


