ACDL研发流程03:像维护代码一样建设文档
ACDL研发流程系列第3篇,共15篇。
1.项目变大以后,代码本身讲不完整个项目
项目还小时,Director往往可以在一次对话中向Agent讲清大部分背景。实现方向即使有偏差,返工成本也有限。
规模上来以后,Agent虽然仍然可以快速读取代码,却不一定知道:
- 某个行为是刻意设计,还是尚未修复的实现偏差;
- 一项限制来自产品要求、安全边界,还是当时的临时做法;
- 一段看似多余的代码是否仍有现实用途;
- 某个测试验证的是长期规则,还是只服务一次实现;
- 当前开发环境是否真的已经运行这份代码;
- 一项已经结束的工作当时有哪些失败、跳过和剩余问题。
如果这些信息只保存在人的记忆、聊天记录和提交标题里,每次换会话、换Agent或隔一段时间继续工作,都需要重新猜测。更危险的是,Agent通常不会因为缺少背景自动停止,它很可能会沿着一组错误假设继续完成一份逻辑自洽的实现。
代码规模只是一个提醒。即使项目不大,只要涉及多任务并行、安全、生产数据、环境发布或长期交付,也需要更早把重要上下文写进仓库。
2.文档是代码的“源码”
在当前项目中,文档不只是代码完成后的使用说明。需求记录为什么要改,已经确认的设计定义系统应该怎样工作。Agent先读取需求和已经确认的设计,再把它们变成代码和测试。从这个意义上说,文档是代码的“源码”。
这个说法不表示所有文档都要在编码前写完。不同文档承担不同职责:
1 | REQ |
设计可以指导后续实现;实施记录不能反过来因为代码已经写出来,就悄悄改变设计;环境记录也不能因为服务器当前恰好这样配置,就自动成为长期架构规则。
当前项目中文档和代码的规模约为1:2。这不是要求项目为了凑比例而增加文字,而是一个经验观察:一个能够长期交给Agent建设的项目,通常需要写下与代码规模相匹配的产品目标、工程规则、实际修改和验证结果。过期、重复或没有实际用途的文档同样应该整理,文档数量从来不是目标。
3.同一类信息只在一个位置完整维护
文档变多以后,真正危险的问题往往不是“没有文档”,而是“有两份都像正确答案的文档”。
因此先明确每类信息由哪里负责:
| 想知道什么 | 先到哪里找 |
|---|---|
| 发现了什么问题、现在准备怎样处理 | ISSUE台账和必要的问题详情 |
| 为什么要改变产品、想得到什么结果 | REQ |
| 系统现在应该怎样工作 | 系统、能力和横切设计 |
| 这一轮准备做什么、实际发生了什么 | 对应ACL、DFL或ERL记录 |
| 某个正式版本实际交付了什么 | 版本与发布说明 |
| 环境现在运行什么、怎样恢复 | 环境记录 |
其它文档需要这些信息时,只保留帮助当前读者理解的摘要,再链接到负责该信息的位置。不要复制一份长期需要手工同步的第二正文。
如果代码和已经确认的设计不一致,也不能简单地说“代码才是真相”。先判断是实现没有做到设计,还是设计已经需要改变,然后走对应流程。
4.编号解决“这是谁”,状态解决“现在能不能用”
标题和文件路径会变化,长期对象需要稳定身份。当前项目使用例如:
STD-:规范;REQ-:需求;SYS-、CAP-、CRS-:系统、能力和横切设计;ADR-、IDX-:重要决策记录和设计索引;ISSUE-:持续跟踪的问题;ACL-、DFL-、ERL-:实施Loop。
编号一旦使用就不回收、不分配给另一件事。标题可以调整,文件也可以在规则允许时移动,但引用的身份保持稳定。
文档状态回答另一个问题:这份内容目前处于什么阶段。
Draft:仍在整理;Proposed或Review:已经提出或进入评审;Accepted:规范、产品或设计已经确认,可以在声明范围内采用;Completed:计划、记录或正式版本已经执行结束;Superseded:已经被更新内容替代,保留用于追溯。
不同对象还可能有自己的业务状态,例如REQ有候选、已选中、已排期,Loop有Ready、In Progress、Review、Completed。不要把文档状态和对象状态混成一个字段,也不要从Completed推断结果一定没有遗留问题。
5.链接让后来的人能够从任何入口继续追踪
编号告诉我们“是哪一项”,状态告诉我们“现在能不能采用”,链接则告诉我们“为什么出现、由什么实现、后来去了哪里”。
一项产品变化常见的关系是:
1 | 问题或反馈 |
这不是要求所有工作都必须经过这些对象,而是说明一旦对象存在,它们之间应该能互相找到。
链接也能减少重复。例如发布说明只需要概括用户能感知的变化,并链接版本总览和实施入口;它不需要再次复制几十条测试输出。
6.Git保存文档结论怎样变化
当前项目把文档和代码放在同一个Git仓库中。设计、实现和测试在同一项工作中变化时,它们能够通过提交和差异保持对应。
当前设计文档应直接表达现在应该怎样工作,不要不断在正文中堆叠“之前如何、后来又如何”。普通变化由Git历史保留;一项重要决定被替代时,才使用ADR或历史记录解释为什么变化。
实施记录和环境证据则不同。它们保存的是当时真实发生的事情,失败候选、跳过项和实际限制不能为了让最终故事更漂亮而回头改写。
7.自然语言负责解释,统一字段负责让工具检查
背景、取舍和原因适合用普通中文说明;编号、状态和关系如果完全依靠工具从自然语言猜测,很容易出错。
所以当前项目同时保留:
- 面向人的正文;
- 文档开头的统一字段;
- ISSUE、REQ和Loop登记表;
- 少量JSON等结构化数据,例如设计要求追踪账本;
- 由结构化数据生成的可读视图。
结构化不等于把所有文档改成表格和JSON。只有需要自动检查、同步或长期引用的信息才进入结构化字段;真正的背景、规则和理由仍然应该写成正常正文。
8.把机械检查交给仓库工具
当编号、状态和链接已经成为项目规则,重复检查适合交给工具:
pnpm docs:check检查文档结构、编号、状态、路径、链接和追踪关系;pnpm trace:render根据设计要求账本重建设计要求视图;- ISSUE工具负责分配问题编号并维护外部关系;
- Loop工具负责创建ACL记录,并按允许的状态变化同步登记表和文档。
工具只能判断格式和关系是否一致,不能决定需求值不值得做、设计是不是合理,也不能代替Director确认Loop结论。
9.文档和代码在同一项工作中保持一致
文档不应该总在代码完成几周以后再补。更可靠的做法是:
1.实施前,REQ和已经确认的设计已经能说明目标和边界;
2.实施中发现设计与现实冲突时,先说明差异,再决定修实现还是回到设计;
3.接口、事务、迁移、错误或其它长期技术约定发生变化时,同步更新负责该结论的能力设计或横切设计;
4.实际提交、测试、失败、跳过和剩余问题随工作写入实施记录;
5.环境发生变化时更新环境记录;
6.得到需要的确认以后,再修改相应状态;
7.提交前运行文档和差异检查。
这不要求每改一行代码都新建文档。修复已经确认设计的局部缺陷,可以直接引用现有设计;不改变含义的错字和链接修正,也不需要制造REQ或Loop。更新哪些文档,只看这项工作真正改变了什么。
10.用“收藏会话”看这些文档怎样配合
假设Director确认员工需要一种方式重新找到重要会话。
REQ先说明员工当前遇到的问题、期望结果、非目标和验收场景。设计再说明收藏属于谁、员工如何操作、失去访问权时怎样处理,以及数据、接口和权限如何实现。
ACL启动时引用这些已经确认的内容,保存本轮起点、范围和验证方法。实施过程中,代码和测试证明实现结果,实施记录保存真实修改和失败。需要实机验证时,环境记录说明当时到底部署了什么。最后如果这项变化进入正式版本,版本记录保存实际纳入范围并由Git标签固定。
这个例子说明的不是“一个功能必须写多少份文档”,而是不同问题由不同文档回答,并且可以沿链接互相追踪。
11.文档建设是一项持续工程
第一次整理文档时,需要建立入口、明确职责并处理明显冲突。之后每项工作只在真正受影响的位置持续维护,而不是几个月以后再集中补写、重新猜测当时发生了什么。
一套文档真正可用的标准很简单:新的Director或Agent从总入口开始,能够找到当前需求和设计,区分进行中与已结束的工作,看到环境当前状态,并追溯正式版本和验证依据。
这些是ACDL能够长期运行的基础。下一章将进一步说明,一项需求怎样从这里进入完整研发流程。