ACDL研发流程03:像维护代码一样建设文档

ACDL研发流程系列第3篇,共15篇。

上一篇:ACDL研发流程02:从想法到项目骨架

下一篇:ACDL研发流程04:需求怎样走完整个ACDL

1.项目变大以后,代码本身讲不完整个项目

项目还小时,Director往往可以在一次对话中向Agent讲清大部分背景。实现方向即使有偏差,返工成本也有限。

规模上来以后,Agent虽然仍然可以快速读取代码,却不一定知道:

  • 某个行为是刻意设计,还是尚未修复的实现偏差;
  • 一项限制来自产品要求、安全边界,还是当时的临时做法;
  • 一段看似多余的代码是否仍有现实用途;
  • 某个测试验证的是长期规则,还是只服务一次实现;
  • 当前开发环境是否真的已经运行这份代码;
  • 一项已经结束的工作当时有哪些失败、跳过和剩余问题。

如果这些信息只保存在人的记忆、聊天记录和提交标题里,每次换会话、换Agent或隔一段时间继续工作,都需要重新猜测。更危险的是,Agent通常不会因为缺少背景自动停止,它很可能会沿着一组错误假设继续完成一份逻辑自洽的实现。

代码规模只是一个提醒。即使项目不大,只要涉及多任务并行、安全、生产数据、环境发布或长期交付,也需要更早把重要上下文写进仓库。

2.文档是代码的“源码”

在当前项目中,文档不只是代码完成后的使用说明。需求记录为什么要改,已经确认的设计定义系统应该怎样工作。Agent先读取需求和已经确认的设计,再把它们变成代码和测试。从这个意义上说,文档是代码的“源码”。

这个说法不表示所有文档都要在编码前写完。不同文档承担不同职责:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
REQ
→说明为什么改变、希望得到什么结果

已经确认的设计
→说明系统现在应该怎样工作

代码和测试
→实现并验证已经确认的行为

实施记录
→保存这一轮实际做了什么、失败了什么、结果怎样

环境记录
→保存环境现在运行什么

版本记录
→保存正式交付最后纳入什么

设计可以指导后续实现;实施记录不能反过来因为代码已经写出来,就悄悄改变设计;环境记录也不能因为服务器当前恰好这样配置,就自动成为长期架构规则。

当前项目中文档和代码的规模约为1:2。这不是要求项目为了凑比例而增加文字,而是一个经验观察:一个能够长期交给Agent建设的项目,通常需要写下与代码规模相匹配的产品目标、工程规则、实际修改和验证结果。过期、重复或没有实际用途的文档同样应该整理,文档数量从来不是目标。

3.同一类信息只在一个位置完整维护

文档变多以后,真正危险的问题往往不是“没有文档”,而是“有两份都像正确答案的文档”。

因此先明确每类信息由哪里负责:

想知道什么 先到哪里找
发现了什么问题、现在准备怎样处理 ISSUE台账和必要的问题详情
为什么要改变产品、想得到什么结果 REQ
系统现在应该怎样工作 系统、能力和横切设计
这一轮准备做什么、实际发生了什么 对应ACL、DFL或ERL记录
某个正式版本实际交付了什么 版本与发布说明
环境现在运行什么、怎样恢复 环境记录

其它文档需要这些信息时,只保留帮助当前读者理解的摘要,再链接到负责该信息的位置。不要复制一份长期需要手工同步的第二正文。

如果代码和已经确认的设计不一致,也不能简单地说“代码才是真相”。先判断是实现没有做到设计,还是设计已经需要改变,然后走对应流程。

4.编号解决“这是谁”,状态解决“现在能不能用”

标题和文件路径会变化,长期对象需要稳定身份。当前项目使用例如:

  • STD-:规范;
  • REQ-:需求;
  • SYS-CAP-CRS-:系统、能力和横切设计;
  • ADR-IDX-:重要决策记录和设计索引;
  • ISSUE-:持续跟踪的问题;
  • ACL-DFL-ERL-:实施Loop。

编号一旦使用就不回收、不分配给另一件事。标题可以调整,文件也可以在规则允许时移动,但引用的身份保持稳定。

文档状态回答另一个问题:这份内容目前处于什么阶段。

  • Draft:仍在整理;
  • ProposedReview:已经提出或进入评审;
  • Accepted:规范、产品或设计已经确认,可以在声明范围内采用;
  • Completed:计划、记录或正式版本已经执行结束;
  • Superseded:已经被更新内容替代,保留用于追溯。

不同对象还可能有自己的业务状态,例如REQ有候选已选中已排期,Loop有ReadyIn ProgressReviewCompleted。不要把文档状态和对象状态混成一个字段,也不要从Completed推断结果一定没有遗留问题。

5.链接让后来的人能够从任何入口继续追踪

编号告诉我们“是哪一项”,状态告诉我们“现在能不能采用”,链接则告诉我们“为什么出现、由什么实现、后来去了哪里”。

一项产品变化常见的关系是:

1
2
3
4
5
6
7
问题或反馈
→REQ
→受影响的设计和必要ADR
→ACL、DFL或ERL
→实施和验证证据
→产品版本
→Git标签

这不是要求所有工作都必须经过这些对象,而是说明一旦对象存在,它们之间应该能互相找到。

链接也能减少重复。例如发布说明只需要概括用户能感知的变化,并链接版本总览和实施入口;它不需要再次复制几十条测试输出。

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能够长期运行的基础。下一章将进一步说明,一项需求怎样从这里进入完整研发流程。