Skip to main content
← All posts
作者:Sagasu

#005-文档的生命周期:从诞生到演化

—— 让文档成为活的产品规范 + 博客 v0.5 搜索功能实战

彩色手绘风格:一只卡皮巴拉站在一个分叉路口,一边是

系列导读:这是《用一份 .md,把想法变成产品》系列的第5篇。在前四篇中,我们建立了文档驱动的理念,定义了三份核心文档,成功实现了博客的 v0.1 到 v0.4。现在,博客已经有了文章列表、分页、分类和标签功能。但随着项目演化,一个新的问题浮现:如何让文档保持鲜活,而不是变成过时的归档文件?


开篇:文档腐化的困境

v0.4 上线两周后,卡比的博客已经发布了20多篇文章。一天晚上,卡比在浏览自己的博客时,突然意识到一个问题:

"我有这么多文章,但每次想找一篇旧文章都要翻好几页,太不方便了。我需要搜索功能!"

卡比兴奋地打开项目文件夹,准备添加搜索功能。但在动手之前,卡比想起了文档驱动开发的原则:"功能变更,先更新文档。"

于是,卡比打开了 spec.md 文件,准备添加搜索功能的需求描述。但当卡比看到文档内容时,愣住了:

文档里还保留着 v0.1 的一些描述,有些功能说明和当前代码已经不一致,甚至还有一些标记为"待定"的部分从未更新过。

"糟糕,我的文档已经过时了..."

这就是文档腐化(Documentation Decay)的问题——即使你写了很好的文档,如果不持续维护,它们很快就会变成无用的文字堆积。

彩色手绘风格:一只沮丧的卡皮巴拉坐在电脑前,屏幕上显示着混乱的文档,有些段落被打上了


一、文档腐化的根源

1.1 为什么文档总是过时?

卡比陷入了思考:"为什么我明明重视文档,却还是让它们过时了?"

仔细分析后,卡比发现了三个根本原因:

原因 1:更新成本高(心理门槛)

场景重现:

  • 开发新功能时,卡比会想:"先把代码写出来,文档等会儿再说"

  • 调试 bug 时,卡比会想:"这只是个小改动,不用更新文档吧"

  • 赶项目进度时,卡比会想:"来不及了,文档下次补"

结果:"下次"永远不会来。

心理分析:

  • 更新文档需要"切换上下文"(从编码思维切换到写作思维)

  • 文档更新没有即时反馈(代码改完能立即看到效果,文档改完看不出什么)

  • 感觉"浪费时间"("我都已经实现了,为什么还要再写一遍?")

原因 2:无人负责(职责不清)

场景重现:

  • 个人项目:只有自己,"反正我记得"(但两个月后就忘了)

  • 团队项目:大家都觉得"应该有人更新",但没人真正负责

问题本质:

  • 没有明确的"文档所有者"(Document Owner)

  • 没有建立"代码更新 = 文档更新"的强制关联

  • 没有制度化的检查机制

原因 3:收益不明(为什么要更新?)

场景重现:

卡比在实现分类功能时,确实更新了 spec.md,但只是简单地添加了几行描述:

"支持文章分类。用户可以按分类查看文章。"

这种描述太笼统,以至于当后来要添加"分类统计"功能时,卡比不确定这算是"新功能"还是"完善现有功能"。

问题本质:

  • 文档更新质量低(敷衍了事)

  • 没有意识到文档的长期价值

  • 把文档当作"任务"而非"资产"

1.2 文档腐化的恶性循环

卡比画了一个循环图:

文档过时 → 开发者不信任文档 → 不参考文档开发 → 更不会更新文档 → 文档更加过时

这就像是一个自我实现的预言:一旦文档开始腐化,就很难再恢复它的权威性。

彩色手绘风格:一个圆形循环图,中间是一只困惑的卡皮巴拉,周围是四个相连的箭头,每个箭头上标注着文档腐化循环的一个阶段。箭头颜色从绿色逐渐变为灰色,象征活力的流失。

1.3 假如文档没更新会怎样?

卡比做了一个思想实验:"假如我现在不更新文档,直接添加搜索功能会怎样?"

可能的后果:

  1. AI 生成的代码可能与现有架构不一致

    • AI 只能看到 v0.2 的文档

    • 生成的搜索功能可能不适配 v0.4 的分类和标签系统

    • 需要大量手动调整

  2. 未来的自己无法理解决策原因

    • 三个月后,卡比想优化搜索

    • 但不记得为什么当初选择了客户端搜索而非服务端搜索

    • 只能重新分析所有代码

  3. 功能扩展变得困难

    • 如果要添加"搜索历史记录"功能

    • 不知道搜索的数据结构是怎么设计的

    • 容易引入不兼容的改动

关键洞察:

文档不是为了"记录已经做了什么",而是为了"支持未来的演化"。


二、文档更新的三种触发时机

卡比意识到,文档更新不应该是"想起来就做",而应该有明确的触发时机。卡比总结了三种场景:

2.1 触发时机 1:需求变更

最常见的场景,也是本篇的核心示例:添加搜索功能。

卡比的实战流程

第 1 步:产品思考——为什么需要搜索?

卡比先问自己:

  • 问题是什么? 博客文章越来越多(已有 20+ 篇),读者很难快速找到想看的内容

  • 用户是谁? 主要是我自己(查找旧文章),其次是博客访客

  • 有多重要? 中等优先级(不是紧急需求,但确实影响体验)

  • 成功标准是什么? 搜索速度快(< 200ms)、结果准确、移动端友好

第 2 步:判断是否需要更新 intent.md

卡比翻开 intent.md,看到项目愿景是:

"构建一个简洁、优雅、易于维护的个人技术博客,用于分享技术见解和方法论实践。"

判断:搜索功能是对"易于维护"和用户体验的增强,但不改变核心愿景。

结论:intent.md 不需要更新。

经验:intent.md 通常只在项目转型时更新(例如从"个人博客"变为"团队知识库")。

彩色手绘风格:卡比坐在咖啡馆里,面前铺着笔记本,正在构思搜索功能。桌上有咖啡杯和画着搜索框草图的纸张。窗外是傍晚的天空,营造出思考的氛围。

第 3 步:更新 spec.md——定义搜索功能

卡比在 spec.md 中添加了新的章节:

功能:全文搜索

用户故事:

  • 作为博客读者,我希望能通过关键词快速找到相关文章

  • 作为内容创作者,我希望能方便地找到自己写过的文章

功能描述:

  • 用户在导航栏看到搜索框

  • 输入关键词后,实时显示匹配结果

  • 搜索范围:文章标题、摘要、正文、标签

  • 结果按相关性排序,最相关的在最前面

  • 点击搜索结果可直接跳转到文章详情页

交互细节:

  • 搜索框支持键盘快捷键(Ctrl+K 或 Cmd+K 打开)

  • 输入时实时显示建议(无需点击搜索按钮)

  • 搜索结果中高亮显示关键词

  • 移动端:搜索图标点击后全屏展开搜索界面

验收标准:

  • 搜索响应时间 < 200ms(50 篇文章场景)

  • 支持中英文搜索

  • 支持模糊匹配(输入"文档"能匹配"文档驱动")

  • 移动端搜索体验流畅

  • 搜索结果准确率 > 90%(手动测试 20 个常见搜索词)

非功能需求:

  • 不影响页面加载速度

  • SEO 友好(搜索引擎仍能抓取所有内容)

  • 无需后端服务器(纯静态实现)

第 4 步:更新 plan.md——技术方案

接下来,卡比在 plan.md 中添加技术实现方案:

搜索功能技术方案

方案选择:

卡比对比了三种搜索方案:

方案 1:服务端搜索(如 Algolia)

  • 优点:功能强大、速度快、支持复杂查询

  • 缺点:需要付费、依赖第三方服务、增加部署复杂度

  • 结论:博客是静态站点,不适合引入服务端依赖

方案 2:客户端全文搜索(如 Fuse.js)

  • 优点:纯前端实现、无需后端、免费

  • 缺点:需要加载所有文章索引(可能影响性能)

  • 结论:适合中小型博客(< 100 篇文章)

方案 3:混合方案(构建时生成索引,客户端搜索)

  • 优点:兼顾性能和灵活性

  • 缺点:实现复杂度稍高

  • 结论:最优方案

最终选择:方案 3

实现步骤:

  1. 构建时生成搜索索引

    • 读取所有文章

    • 提取标题、摘要、正文、标签

    • 生成 JSON 格式的索引文件

    • 优化索引大小(去除停用词、压缩)

  2. 客户端搜索组件

    • 使用 Fuse.js 进行模糊搜索

    • 实现搜索框界面

    • 添加键盘快捷键支持

    • 实现搜索结果高亮

  3. 性能优化

    • 索引文件懒加载(用户打开搜索时才加载)

    • 防抖处理(避免频繁搜索)

    • 搜索结果限制(最多显示 20 条)

数据结构:

搜索索引的基本结构:

  • 每篇文章包含:ID、标题、摘要、内容片段、标签、路径

  • 索引文件大小预估:50 篇文章约 100-200KB

组件设计:

新增搜索相关组件:

  • SearchBar:搜索框和触发按钮

  • SearchModal:搜索弹窗(包含搜索框和结果列表)

  • SearchResult:单条搜索结果展示

第 5 步:让 AI 生成代码

有了清晰的文档,卡比向 AI 提供了完整的上下文:

"基于以下文档,为博客生成搜索功能的完整实现。

[spec.md 的搜索功能章节]
[粘贴 spec.md 中的搜索功能描述]

[plan.md 的技术方案]
[粘贴 plan.md 中的搜索技术方案]

[当前项目状态]

  • v0.4 已实现:文章列表、分类、标签

  • 技术栈:Next.js 14 + React + Tailwind CSS

  • 文章存储:Markdown 文件(/content/posts/*.md)

[约束条件]

  • 纯前端实现,无需后端服务器

  • 搜索索引在构建时生成

  • 使用 Fuse.js 实现模糊搜索

  • 支持键盘快捷键(Ctrl+K / Cmd+K)

请生成:

  1. 索引生成脚本

  2. 搜索组件

  3. 搜索弹窗

  4. 样式文件

  5. 配置文件更新"

AI 根据文档生成了完整的代码实现。

第 6 步:验证和测试

卡比按照 spec.md 的验收标准逐一测试:

功能测试:

  • ✅ 搜索框正常显示

  • ✅ 键盘快捷键有效(Ctrl+K 打开搜索)

  • ✅ 输入时实时显示结果

  • ✅ 搜索结果准确(测试了"文档驱动"、"AI"、"博客"等关键词)

  • ✅ 关键词高亮正常

  • ✅ 点击结果可跳转

性能测试:

  • ✅ 搜索响应时间:平均 50ms(远低于 200ms 目标)

  • ✅ 索引文件大小:23 篇文章 = 85KB(可接受)

  • ✅ 页面加载速度未受影响

移动端测试:

  • ✅ 搜索界面在移动端正常显示

  • ✅ 虚拟键盘不遮挡搜索结果

  • ✅ 触摸操作流畅

结果:所有验收标准均通过! 🎉

彩色手绘风格:卡比在电脑前兴奋地测试搜索功能,屏幕上显示搜索结果列表,关键词被高亮显示。旁边有一个对勾清单,所有项都被勾选。背景有庆祝的彩带。

第 7 步:同步提交文档和代码

卡比在提交代码时,遵循了"文档和代码同步"的原则:

提交信息:
"feat: add search functionality with complete documentation

  • Updated spec.md: added search feature requirements and acceptance criteria

  • Updated plan.md: added technical implementation approach

  • Implemented: search index generation, search components, keyboard shortcuts

  • Tested: all acceptance criteria passed

Ref: v0.5 milestone"

2.2 触发时机 2:技术重构

场景:假设三个月后,卡比发现客户端搜索在文章超过 100 篇时变慢了,决定迁移到 Algolia。

更新流程:

  1. 技术债务识别:记录为什么要重构

  2. 更新 plan.md:描述新的技术方案

  3. 验证 spec.md:确认功能需求不变(用户体验保持一致)

  4. 代码实现:按新方案重构

  5. 测试验证:确保满足原有验收标准

关键点:

  • 技术重构通常只更新 plan.md

  • spec.md 中的用户需求应该保持不变

  • 如果用户体验有变化,需要同步更新 spec.md

2.3 触发时机 3:Bug 修复

场景:用户反馈搜索结果排序不够准确。

判断流程:

第 1 步:这是文档问题还是实现问题?

  • 检查 spec.md:有没有明确定义排序规则?

    • 如果没有 → 这是文档遗漏,需要补充需求

    • 如果有 → 这是实现问题,按文档修复代码

第 2 步:更新文档(如果需要)

假设 spec.md 中只写了"结果按相关性排序",但没有明确"相关性"的定义。

更新 spec.md,增加:

搜索结果排序规则:

  1. 标题完全匹配:权重最高

  2. 标题部分匹配:权重第二

  3. 摘要匹配:权重第三

  4. 正文匹配:权重最低

  5. 同等权重下,按发布日期倒序

第 3 步:修复实现

根据更新后的文档,调整搜索算法的权重配置。

第 4 步:提交记录

提交信息:
"fix: improve search result ranking

  • Updated spec.md: clarified search ranking criteria

  • Updated plan.md: adjusted Fuse.js scoring weights

  • Fixed: search results now properly ranked by relevance

Closes #issue-number"

彩色手绘风格:一个工作流程图,显示三种触发文档更新的场景。左侧是


三、文档版本管理

3.1 Git 工作流:文档和代码的关系

卡比采用了"文档和代码同步提交"的策略。

基本原则:

  1. 功能分支中同步更新

    • 创建 feature/search 分支

    • 先编辑文档(spec.md 和 plan.md)

    • 再实现代码

    • 一起提交

  2. Commit 信息规范

    • docs: - 纯文档更新(如修正错别字、补充说明)

    • feat: - 功能实现(必须包含文档更新)

    • fix: - Bug 修复(如果涉及文档,一起更新)

    • refactor: - 技术重构(更新 plan.md)

  3. 典型提交流程

创建功能分支:
"git checkout -b feature/search"

编辑文档:
(更新 docs/spec.md 和 docs/plan.md)

实现功能:
(编写代码)

同步提交:
"git add docs/ src/
git commit -m 'feat: add search feature with updated docs'
git push origin feature/search"

3.2 文档仓库设计

卡比的博客项目采用的结构:

项目根目录

为什么放在项目内?

  • 文档和代码版本一致

  • 容易保持同步

  • 部署时可以自动生成文档站点

其他可选方案:

  • 多项目场景:单独的文档仓库(monorepo 或独立仓库)

  • 大型团队:使用 Confluence 等平台(但仍需与代码同步)

彩色手绘风格:一个 Git 提交历史可视化图,显示多个提交节点。每个节点同时包含

3.3 冲突解决

场景:假设卡比同时在两个分支上工作:

  • feature/search:添加搜索功能

  • feature/comments:添加评论系统

两个分支都修改了 spec.md,如何处理?

解决方案:

  1. 按功能优先级合并

    • 先合并 feature/search(假设优先级更高)

    • 再合并 feature/comments 时,处理文档冲突

  2. 模块化文档结构

    • 将 spec.md 拆分为多个章节

    • 每个功能独立章节,减少冲突

  3. 定期同步主分支

    • 功能开发期间,定期 rebase 主分支

    • 及时发现和解决冲突

经验:

  • 大多数文档冲突都是"追加式"的(两个功能各自添加章节)

  • 真正的冲突通常是改动了共享部分(如数据模型)

  • 这种情况下,需要开会讨论优先级


四、文档质量保障

4.1 自动化检查

卡比为博客项目添加了文档质量检查。

检查项目:

  1. 链接有效性

    • 检查文档中的所有链接是否有效

    • 避免出现 404 链接

  2. 必填字段验证

    • intent.md 必须包含:项目愿景、目标用户、核心问题、成功标准

    • spec.md 必须包含:功能列表、用户旅程、验收标准

    • plan.md 必须包含:技术栈、架构设计、数据模型

  3. 文档一致性

实现方式:

在 CI/CD 中集成检查脚本:

  • 每次 Pull Request 时自动运行

  • 检查失败则无法合并

  • 保证文档质量的底线

4.2 Review 机制

个人项目的自我 review:

卡比的实践:

  1. 睡一觉再看:写完文档不立即提交,第二天再看一遍

  2. 反向验证:根据文档尝试复述需求,看是否遗漏

  3. 假想他人阅读:想象自己三个月后看这份文档,能否理解?

团队项目的 review checklist:

文档 Review 的 7 个必查项:

  1. 意图是否清晰?(能否快速理解为什么要做)

  2. 功能描述是否完整?(有没有遗漏边界条件)

  3. 技术方案是否可行?(是否考虑了风险)

  4. 是否有遗漏的边界条件?(如错误处理、极端情况)

  5. 是否与现有架构一致?(不会引入技术债务)

  6. 是否容易演化?(未来扩展是否方便)

  7. 是否有示例和测试标准?(如何验证实现正确)

彩色手绘风格:卡比坐在书桌前,面前是一份文档和一个检查清单。卡比用放大镜仔细检查文档内容,周围有几个已勾选的对勾标记。背景是整洁的工作环境。

4.3 AI 辅助质量检查

卡比还尝试了使用 AI 来辅助文档质量检查。

使用场景:

  1. 一致性检查
    提示词:"请检查 spec.md 和 plan.md 是否一致。spec.md 中提到的所有功能,plan.md 中是否都有对应的实现方案?"

  2. 完整性检查
    提示词:"请检查这份 spec.md 是否完整。是否遗漏了错误处理、权限控制、性能要求等方面?"

  3. 可读性检查
    提示词:"请评估这份文档的可读性。是否有地方表达不清晰、术语使用不当、或逻辑跳跃?"

经验:

  • AI 可以发现明显的遗漏和不一致

  • 但最终判断仍需人工决策

  • 适合作为自我 review 的辅助工具


五、经验总结:让文档成为活的资产

5.1 博客 v0.5 的最终成果

彩色手绘风格:前后对比图。左侧是 v0.4(没有搜索),卡比在翻页找文章,表情苦恼。右侧是 v0.5(有搜索),卡比轻松地输入关键词,立即找到想要的文章,表情满意。

通过完整的文档驱动流程,卡比成功为博客添加了搜索功能:

功能成果:

  • ✅ 搜索速度快(< 50ms 响应)

  • ✅ 搜索结果准确

  • ✅ 支持键盘快捷键

  • ✅ 移动端体验良好

文档成果:

  • ✅ spec.md 更新了搜索功能需求

  • ✅ plan.md 记录了技术方案和决策理由

  • ✅ CHANGELOG.md 记录了版本变更

  • ✅ 所有文档与代码保持同步

开发效率:

  • 总耗时:约 3 小时(包括文档编写和代码实现)

  • 如果没有文档驱动,预估需要 5-6 小时(更多试错和返工)

  • 提升约 40-50% 的效率

5.2 文档演化的核心洞察

通过这次实践,卡比总结了三个核心洞察:

洞察 1:文档更新不是负担,而是清晰思考的必需品

传统观念:

  • "文档是额外工作,占用开发时间"

  • "我已经想清楚了,不需要写文档"

实际体验:

  • 写文档的过程帮助发现思考盲区

  • 文档让决策过程可追溯

  • 文档降低了未来维护的成本

数据对比:

  • 写文档的时间:约 30 分钟

  • 避免返工节省的时间:约 1-2 小时

  • 净收益:节省 30-90 分钟

洞察 2:文档的价值随着项目演化而增长

v0.1 时:

  • 文档主要服务于"理清思路"

  • 价值:让第一版实现顺利

v0.5 时:

  • 文档成为"演化地图"

  • 价值:让每次迭代有依据、可追溯

未来(v1.0+):

  • 文档将成为"团队协作的通用语言"

  • 价值:降低沟通成本、支持新成员快速上手

关键比喻:

文档就像复利投资:

  • 初期回报不明显(需要时间积累)

  • 长期回报巨大(价值指数增长)

  • 越早开始,收益越大

洞察 3:活文档需要制度保障,而非依赖觉悟

错误做法:

  • 依靠"自觉性"更新文档(不可持续)

  • 事后补文档(容易遗忘细节)

正确做法:

  • 建立强制关联(代码更新 = 文档更新)

  • 自动化检查(CI/CD 集成)

  • 制度化 review(文档 review 纳入流程)

个人实践:

  • 设置 Git hook:提交代码时检查是否更新文档

  • 使用 checklist:每次功能完成前过一遍检查清单

  • 定期回顾:每个月回顾一次文档,补充遗漏

彩色手绘风格:一棵生长的树,树根是

5.3 对"活文档"的重新定义

传统观念中,文档是"静态的记录":

  • 写完就不动了

  • 存放在某个角落

  • 需要时才翻出来看

文档驱动开发中,文档是"活的规范":

  • 随项目演化而演化

  • 始终与代码保持同步

  • 是开发过程的一部分,而非附属品

活文档的三个特征:

  1. 动态性:随时更新,反映最新状态

  2. 权威性:是项目的 Single Source of Truth

  3. 演化性:支持项目持续迭代

如何判断文档是"活"的还是"死"的?

死文档的标志:

  • 最后更新时间是几个月前

  • 文档描述与实际功能不符

  • 开发者不参考文档,直接看代码

活文档的标志:

  • 每次功能变更都同步更新

  • 新成员优先看文档,而非代码

  • 文档是讨论需求的依据


结语:文档的生命力来自持续维护

通过 v0.4 到 v0.5 的演化,卡比深刻理解了文档生命周期管理的重要性:

我们学到了什么?

1. 文档腐化是可以预防的

问题根源:

  • 更新成本高、无人负责、收益不明

解决方案:

  • 降低成本:建立模板和自动化工具

  • 明确责任:文档和代码同步更新

  • 凸显收益:让文档真正驱动开发

2. 三种触发时机覆盖所有场景

需求变更:

  • 最常见的场景

  • v0.5 搜索功能是典型案例

技术重构:

Bug 修复:

  • 判断是文档问题还是实现问题

  • 必要时补充文档

3. 制度保障比个人觉悟更重要

不要依赖"自觉":

  • 建立 Git 工作流

  • 集成 CI/CD 检查

  • 制度化 review 流程

让更新变得自然:

  • 文档和代码一起提交

  • 自动化检查降低门槛

  • 正反馈循环(文档有用 → 愿意维护)

下一步

博客现在已经有了列表、分类、标签和搜索功能,已经是一个相当完整的博客系统了。但随着内容增多、访问量增加,新的挑战也会出现:

  • 性能优化:如何保证加载速度?

  • SEO 增强:如何让搜索引擎更好地收录?

  • 多作者支持:如果要变成团队博客怎么办?

  • 国际化:如何支持中英文切换?

下一篇(第6篇),我们将探讨规模化实践——当项目从简单博客演化为复杂系统时,文档驱动如何帮助我们管理复杂度。

记住:文档不是一次性工作,而是持续演化的过程。让文档成为项目的一部分,而非负担。


给读者的行动建议

如果你也想让文档"活起来",从现在开始:

  1. 检查你的文档状态

    • 打开项目文档,检查是否过时

    • 如果发现不一致,立即更新

  2. 建立更新机制

    • 设置 Git hook 或 CI 检查

    • 制定"文档和代码同步"的规则

  3. 定期回顾

    • 每月至少回顾一次文档

    • 删除过时内容,补充遗漏

  4. 培养习惯

    • 功能开发前,先更新文档

    • 代码提交时,检查文档是否同步

  5. 分享经验

    • 记录文档实践的心得

    • 在团队中推广文档驱动理念

最重要的是:把文档当作项目的"大脑",而非"档案室"。


资源和工具

本系列文章:

  • 第 1 篇:为什么我们需要文档驱动开发?

  • 第 2 篇:三份文档,构建你的产品蓝图

  • 第 3 篇:让 AI 成为你的文档执行者

  • 第 4 篇:从 v0.2 到 v1.0 的完整演化

  • 第 5 篇:文档的生命周期:从诞生到演化(本篇)

工具推荐:

  • Cursor - AI 代码编辑器

  • Claude - AI 助手

  • markdown-link-check - 文档链接检查

  • Git hooks - 自动化检查


感谢阅读! 🎉

如果你觉得这篇文章有帮助,欢迎分享给更多人。下一篇文章,我们将探讨如何将文档驱动扩展到更复杂的场景。

让我们一起,用活文档支撑产品的持续演化!