我用 2 个 Skill 解决AI开发如何记录文档的问题

3 阅读8分钟

我用 AI 写了三个月代码,然后我再也看不懂自己写的东西了

一个熟悉的故事

去年我开始大量用 Claude Code 辅助开发。速度确实快——一个下午能出一个以前要两天的功能。但渐渐地我发现了一个问题:三个月前写的东西,我自己都看不懂了。

不是代码写得差。代码本身还好。是因为没有文档——或者说,有文档,但文档跟代码对不上。

列表接口的 spec 里写的是"支持按状态筛选",但代码里加了七八个筛选条件,没有一个更新过文档。数据库表里多了三个字段,接口规范里完全没有提及。当我想加一个新功能的时候,我不知道该相信 spec 还是相信代码。

这是 AI 时代催生的一种新型技术债。AI 写代码太快了,文档永远跟不上。


两个真正的问题

我把这个现象归结为两个独立但相关的问题。

第一个问题:文档腐化。

传统项目里文档腐化已经够烦了。AI 时代更严重,因为生产速度被放大了好几倍,但维护文档的习惯没有跟上。更糟的是,很多人(包括我自己)会在某个需求开始前写一份 spec,然后在开发过程中随着需求变化多次修改,最后项目里存着三四个版本的"spec-v2-final.md",没有人知道哪个是最新的。

第二个问题:AI 的"立刻行动"倾向。

这个更隐蔽。AI coding 工具有一个天然的行为模式:理解需求 → 立刻写代码。它不会主动说"我先把方案写出来你确认一下",而是直接开干。这在需求清晰的时候很好,但在需求模糊、或者理解有偏差的时候,改错方向的代码比没有代码更难处理——因为你得先把错的删掉,再重新来过。


我做了一个工具

过去几个月我一直在想怎么解决这两个问题,最后做了一套叫 doc-first-dev 的东西:一组可以安装到 Claude Code 的 Agent Skills,把"文档先行"这套工作流强制固化下来。

核心是两个命令:

  • /spec-first:管理从需求到交付的完整开发周期。每次有新需求或变更,先写/更新文档,确认通过再开发,开发完再跑验收。
  • /whylog-record:在任务结束后把这次的决策背景记录下来——考虑过哪些方案,为什么选现在这个,有什么取舍。

两个命令一起用,才能回答开发中最重要的两个问题:现在的代码是什么样的(spec)和为什么是这个样子(决策日志)。


三个我觉得值得说的设计决策

1. 确认门:分析和动手之间的强制停顿

/spec-first 的工作流里,有一个我最看重的机制:在 AI 开始写代码之前,必须经过一次用户确认

AI 会先分析需求,读代码,把影响到的接口、数据库结构、代码位置整理成文档,然后展示"改之前是什么样,改之后会是什么样"的对比。只有我点击"确认通过,开始开发",它才会动代码。

这个设计看起来简单,但背后的逻辑很重要:确认门把"理解"和"执行"强制解耦了

在没有这个机制的时候,AI 经常在我话还没说完时就开始写代码了。有时候方向对,有时候不对。不对的时候,我得花时间解释"不是这个意思",然后等它重写。有了确认门之后,我们先把"方向"对齐,再谈"执行"。返工少了很多。

如果在确认环节我觉得方向不对,可以补充说明,AI 会重新分析;如果需求本身变了,也可以在这里调整范围。改文档比改代码便宜。

2. Spec 和决策日志分开存

另一个我思考了很久的问题是:文档里该放什么,不该放什么

我见过很多项目的 spec 越写越臃肿,里面夹杂着"2023年10月我们讨论过方案A,最终选了方案B,因为..."这类历史记录。这些内容对新人有价值,但每次随机读取 spec 时都要跳过它们。

doc-first-dev 的做法是把两类信息分开存:

  • docs/plans/<模块>/ 里的 spec 只回答"现在是什么样"——当前的接口规范、数据库设计、代码结构。就地更新,永远只有一份,历史版本交给 git 管理。
  • docs/decisions/log.md 只回答"为什么是这个样子"——方案选择、取舍背景、考虑过但放弃的替代方案。顺序追加,不覆盖。

这个分法的好处在于:spec 保持精简,可以快速读完;决策日志保留完整上下文,在需要回溯历史的时候去查。两者的读写模式根本不同——spec 是随机读写,决策日志是顺序追加——分开存才能让各自保持最适合自己的形态。

代码里我们已经很自然地把变量命名(what)和注释(why)分开。文档里做同样的分离,其实是一件很自然的事。

3. 三角一致性:接口 ↔ 数据库 ↔ 代码,三角对齐

最后一个设计是在 spec 更新完成后的自动检查。

我发现一类高频错误是:数据库加了一个字段,接口规范里没有更新,然后代码里用了这个字段,但调用方不知道可以传这个参数。或者反过来,接口文档里写了某个查询条件,但数据库里没有对应的索引,代码里也没有处理。

doc-first-dev 在每次分析完之后会做三角校验:接口规范中的字段、数据库设计中的字段、代码地图中的方法签名,三者必须对齐。发现不一致时会立刻暴露,并且问你"以代码为准还是以 spec 为准",让你来做决定。

这个机制解决的不是什么高深问题,就是那种"我以为我都改完了但其实漏了一处"的低级错误。但这类错误在 AI 开发中特别容易出现,因为 AI 改代码的范围有时候超出你的预期,而你没有一个系统地检查全貌的方法。


一次典型的使用过程是什么样的

举个具体的例子。假设我要给一个列表接口加"按作者筛选"的功能:

/spec-first 给文章列表接口加一个按作者筛选的参数,支持模糊匹配

接下来:

  1. AI 读当前的 spec,找到相关接口和数据库表,分析影响范围。
  2. 它把需要修改的内容整理出来:接口规范加 author 参数、数据库查询逻辑说明、受影响的 Mapper 方法。展示改前改后的对比。
  3. 我检查一遍,觉得没问题,点"确认通过,开始开发"。
  4. AI 开始改代码——Mapper、Service、Controller,按顺序来。
  5. 改完构建一遍,然后自动进入验收:实际调用 POST /article/listauthor=张三,检查返回结果里所有文章都包含"张三"。
  6. 验收通过,输出简报:改了哪些文件,验收结果是什么。

整个过程我只需要在确认门那里介入一次。其余的它自己处理。


适合谁用,不适合谁用

说实话,这套工具不是适合所有场景的。

适合:

  • 你在维护一个要持续迭代的项目,而不是一次性脚本
  • 你(或你的团队)用 AI 写了大量代码,但文档状态已经一团糟
  • 你希望 AI 的每次修改都有迹可循,可以回溯

不太适合:

  • 纯探索性的原型,你只是想快速验证一个想法
  • 完全不在意文档的快速实验
  • 项目生命周期很短,文档的投资回报不合算

我自己的用法是:新项目的早期探索阶段先不用,等方向确定了、开始认真迭代了,再引入这套工作流。


安装

如果你想试试:

npx skills add zzusp/doc-first-dev

安装完之后,在你的项目里运行 /spec-first 加上一句需求描述,它会自动检测是否需要初始化,然后走流程。

项目地址:github.com/zzusp/doc-f…


写这个工具的出发点很简单:我不想三个月后看不懂自己写的代码。目前用下来,文档腐化的问题确实好了很多。如果你有类似的困扰,可以试试。有什么问题或者想法,欢迎在评论区聊。