让文档跟着代码走

2 min read
Zekari
文档软件工程自动化Purikura 项目

文档总是过时的

文档会腐烂。

不是因为团队懒惰。是因为熵增是自然规律。代码每天在变,文档需要人工同步。这个过程消耗能量,需要纪律,依赖记忆。任何一个环节松懈,文档就开始偏离真相。

大多数团队的应对方式是"加强文档审查"、"建立文档规范"、"定期更新文档"。这些方法试图用更多的纪律对抗熵增。

但纪律是最稀缺的资源。

真正有效的方法不是更频繁的手工维护,而是减少需要手工维护的文档数量。让文档"活"起来——跟随代码自动更新,而不是依赖人的记忆。

文档的三种生命形态

文档不是单一类型。它有三种形态,每种形态有不同的生命周期。

第一种:活文档。 它就是代码本身。函数签名、类型定义、代码注释。这些文档随代码一起编辑、一起提交、一起审查。它们永远不会过时,因为它们就是真相。

第二种:半自动文档。 它从代码生成,但需要模板和规则。API参考、数据库Schema、组件清单。这些文档由工具扫描代码自动生成。人定义生成规则,机器执行更新。

第三种:手工文档。 架构设计、部署流程、开发指南。这些文档无法从代码推导,必须由人编写。它们更新最慢,也最容易腐烂。

这不是武断的分类。它基于一个简单的原则:文档离代码越近,越不容易过时

活文档嵌入代码中,零距离。半自动文档通过工具连接代码,距离可控。手工文档依赖人工同步,距离最远。

减少文档腐烂的方法就是尽可能多地使用前两种,尽可能少地依赖第三种。

💡 Click the maximize icon to view in fullscreen

活文档:代码即文档

最好的文档就是代码本身。

/**
 * 计算用户的积分消耗成本
 *
 * @param credits - 用户消耗的积分数量
 * @param vendorCost - 厂商API的实际成本(美元)
 * @returns 利润率百分比
 */
function calculateProfitMargin(credits: number, vendorCost: number): number {
  const revenue = credits * 0.0483  // Pro方案单积分价值
  return (revenue - vendorCost) / revenue
}

这段代码的文档不会过时。因为函数签名、参数类型、返回值都是编译器验证的。注释紧挨着代码,修改代码时很难忽略注释。

这种文档的维护成本最低。开发者不需要额外的步骤,不需要切换到另一个文件,不需要记得"别忘了更新文档"。文档就在眼前。

但活文档有局限。它只能描述单个函数或类的行为,无法展示系统的全貌。这时需要第二层。

半自动文档:让机器做记忆的工作

当系统有50个API时,没人能记住每个API的参数和返回值。这时需要API参考文档。

但手工维护API参考是灾难。每次接口变更,都要记得更新两个地方:代码和文档。人的记忆不可靠。

解决方法是让机器扫描代码,自动生成文档。

# 代码提交时自动触发
git commit → pre-commit hook → 扫描代码 → 生成文档 → 提交文档

开发者只需要写好代码注释(活文档),工具自动汇总成API参考(半自动文档)。维护的负担减少了一半。

文档生成不应该是手动命令。它应该绑定在开发流程的关键节点:

  • 提交前:pre-commit hook生成文档,确保文档和代码一起提交
  • 构建时:CI流程生成文档,确保文档和部署同步
  • 发布后:自动部署文档站点,确保用户看到的是最新版本

自动化的关键是"让它成为流程的一部分,而不是额外的任务"。

在Purikura项目中,我们用TypeDoc从TypeScript代码生成API文档,用脚本从数据库Schema生成表结构文档。这些文档每次提交时自动更新,开发者无需手工维护。

手工文档:不得不做的事

有些文档无法自动生成。

架构设计解释"为什么这样设计"。部署流程记录"在什么环境做什么操作"。这些知识无法从代码推导。

手工文档是必需的,但应该被最小化。

原则一:只写无法自动化的内容。 如果某个信息可以从代码生成,就不要手工编写。比如API参数列表属于半自动文档,不应该出现在架构设计文档中。

原则二:用图表代替大段文字。 一张流程图胜过一千字描述。Mermaid图表嵌入在Markdown中,修改方便,版本控制友好。就像API文档标准中的成本计算流程图。

原则三:在重大变更时强制更新。 架构变更、部署流程变更、API设计变更——这些事件必须触发文档更新。不是靠自觉,是靠流程约束。

💡 Click the maximize icon to view in fullscreen

为什么自动化优先

有人会说:"写文档也没那么费时间,手工维护就好。"

问题不在时间,在可靠性。

人会忘记。人会疲倦。人会在deadline前选择跳过"非关键步骤"。文档更新就是这种"非关键步骤"——当它被跳过时,系统不会崩溃,测试不会失败,用户不会抱怨。

但文档会悄悄腐烂。三个月后,没人知道这个函数为什么这样设计。六个月后,新人看着代码和文档的差异,不知道该相信哪个。

自动化不是为了节省时间,是为了确保事情一定会发生。

就像防御式编程不是因为程序员水平差,而是承认人不可能记住所有边界条件。文档自动化不是因为团队懒,而是承认人的记忆不可靠。

自动化不是免费的。

建立文档生成流程需要时间。配置CI需要学习。编写生成脚本需要调试。这些前期成本是真实的。

但这是一次性投入。流程建立后,它会持续运转,不需要额外维护。而手工文档是持续成本,每次代码变更都要重复。

选择取决于时间尺度。如果项目只会存在三个月,手工文档可能更快。如果项目会持续一年以上,自动化是唯一可持续的选择。

文档是代码的镜像

文档不是附加物。它是系统的另一种表达。

代码描述"怎么做",文档描述"为什么做"和"如何使用"。两者应该同步演进,而不是代码在前、文档在后。

当文档落后于代码,说明流程有问题。要么文档分类错误(应该是活文档或半自动文档,却被当成手工文档维护),要么缺少自动化工具,要么团队对文档重要性认识不足。

让文档跟着代码走,不是加强纪律,是改变系统设计。把更多文档推向活文档和半自动文档,减少手工文档的依赖。让自动化成为流程的一部分,而不是额外的负担。

文档衰败是熵增的自然结果。但熵增可以被延缓,只要你理解文档的三种形态,并为每种形态选择正确的维护策略。

Related Posts

Articles you might also find interesting

文档标准是成本计算的前提

3 min read

API文档不只是写给开发者看的。它定义了系统的边界、成本结构和可维护性。统一的文档标准让隐性成本变得可见。

API文档
Read More
Featured

定价界面优化的三层方法

4 min read

数据诚实、决策引导、视觉精调——三层递进的优化方法。从移除虚假功能到帮助用户选择,再到像素级修复,每一步都在解决真实问题

UI/UX定价策略
Read More

用 AI Agents 加速测试环境配置

3 min read

测试环境的配置是重复的琐事。环境变量、测试数据库、配置文件——这些步骤消耗时间但不产生直接价值。AI agents 改变了这个等式。

Claude Code测试
Read More

API 测试各种边界情况

2 min read

边界情况是系统最脆弱的地方,也是最容易被忽略的地方。测试边界情况不是为了追求完美,而是为了理解系统的真实边界。

API测试
Read More

离屏渲染:照片捕获为什么需要独立的 canvas

2 min read

实时流与静态合成的本质冲突,决定了系统必须分离。理解这种分离,就理解了架构设计中最重要的原则。

架构设计前端开发
Read More

集中式配置:让 Reddit 组件脱离重复泥潭

2 min read

当同一份数据散落在多个文件中,维护成本呈指数级增长。集中式配置不是技术选择,而是对抗熵增的必然手段。

架构设计React组件
Read More

CRUD 操作

2 min read

四个字母背后,是数据的生命周期,是权限的边界,也是系统设计的基础逻辑

系统设计软件工程
Read More

双重导出管道的架构选择

2 min read

在用户生成内容场景中,速度与质量的权衡决定了导出架构。理解两种不同管道的设计逻辑,能够更准确地把握产品体验的边界。

架构设计图像导出
Read More

端到端 Postback 模拟测试

2 min read

真实的测试不是模拟完美的流程,而是重现真实世界的混乱。Postback 测试的价值在于发现系统在不确定性中的表现。

测试API
Read More

错误隔离

3 min read

失败是必然的。真正的问题不是失败本身,而是失败如何蔓延。错误隔离不是为了消除失败,而是为了控制失败的范围。

系统设计可靠性工程
Read More

Purikura的页面系统

3 min read

通过五层分层继承复用架构,实现零代码修改的页面生成系统。从类型定义到页面渲染,每一层专注单一职责,实现真正的数据驱动开发。

架构设计React
Read More

重复数据的迁移实践:从 N 个文件到 1 个真相源

3 min read

当同一份 Reddit posts 配置散落在多个文件中,维护成本以文件数量指数增长。迁移到集中式配置不是技术选择,而是对复杂度的清算。

架构设计配置管理
Read More

Git Hooks 驱动的文档同步

2 min read

文档不会自动更新,除非你让它自动更新。Git Hooks 是最接近代码变更的触发点,也是对抗文档腐烂最有效的位置。

Git自动化
Read More

在运行的系统上生长新功能

3 min read

扩展不是推倒重来,而是理解边界,找到生长点。管理层作为观察者和调节器,附着在核心系统上,监测它,影响它,但不改变它的运行逻辑。

系统设计架构
Read More

实现幂等性处理,忽略已处理的任务

3 min read

在代码层面识别和忽略已处理的任务,不是简单的布尔检查,而是对时序、并发和状态的深刻理解

系统设计并发控制
Read More

分层修复

3 min read

生产问题没有银弹。P0 止血,P1 加固,P2 优化。优先级不是排序,而是在不确定性下的决策框架。

工程实践问题修复
Read More

多厂商 AI 调度:统一混乱的供应商生态

3 min read

当你依赖第三方 AI 服务时,单点故障是最大的风险。多厂商调度不只是技术架构,更是对不确定性的应对策略。

Purikura 项目系统架构
Read More

分布式 Workers 的解耦设计

3 min read

通过微服务架构和队列系统,实现高可用的 AI 任务处理。从单体到分布式,每个设计决策都是对复杂度的权衡。

Purikura 项目系统架构
Read More

Studio 前端架构:从画布到组件的设计思考

3 min read

深入 Purikura Studio 前端架构设计,探讨 DOM-based 画布、状态管理和组件化的实践经验

Purikura 项目前端架构
Read More

Studio 系统架构:从状态机到端到端流程

3 min read

深入 Studio 系统的状态管理中心、组件协调机制和 AI 生成的完整数据流,理解前后端集成的设计逻辑

Purikura 项目系统架构
Read More

Context 驱动的认证状态管理

3 min read

认证系统的核心不在登录按钮,而在状态同步。如何让整个应用感知用户状态变化,决定了用户体验的流畅度。

软件设计认证系统
Read More

第三方回调的状态映射完整性

5 min read

KIE.AI 视频生成的三个修复揭示了一个本质问题:回调不只是接收结果,是建立状态映射。没有 vendor_task_id,系统就失去了追溯能力。

Purikura 项目系统设计
Read More

统一积分系统的设计实践

2 min read

从多套积分到单一积分池的架构演进,以及背后的原子性、一致性设计

系统架构数据库设计
Read More

幂等性检查

1 min read

在不确定的系统中,幂等性检查是对重复的容忍,是对稳定性的追求,也是对失败的预期与接纳

系统设计分布式系统
Read More