第35章:增强工具链:Bonus Skills 实战

"核心技能把需求变成能跑的代码。增强技能管后面的事:代码能活多久、别人看得懂吗、文档跟得上吗。"

第 8 章讲过 goal-workflow 的七步流水线:/prd、/prd-to-spec、/to-issues、/goal、/review-it、/note-it、/ship-it。七个核心技能串成一条线,把需求一路推到上线。

这一章讲七个技能。/refactor 管重构,/modern-go 管 Go 代码现代化,/insight-diagram 管画图,/code-to-spec 管逆向文档,/humanize-it 管去 AI 味,这五个是流水线外的增强技能。/note-it 和 /ship-it 在流水线里,第 8 章各提了一句,这里展开讲。

这一章拿 goscapy 当例子。goscapy 是我写的一个 Go 网络库,把 Python Scapy 搬到 Go 生态,不依赖 libpcap、不用 CGO。给它加 IPv6 扩展头支持的过程中,这七个技能轮番上场。一个技能一节,说清楚它干什么、怎么干、什么时候用。

35.1 /refactor:专家级重构

/refactor 基于 Martin Fowler 的《重构》第二版。这本书把重构做成了一门手艺:先认出坏味道,再挑一个手法,小步改,改完跑测试。/refactor 把这套东西装进了 skill 里。

35.1.1 五条铁律

skill 开头列了五条 Golden Rules,说这是不能碰的红线。碰了任何一条,重构就变成了乱改。

一,行为不变。变的是代码怎么写,不是它做什么。重构前有测试,重构后测试照样过。引入行为变更不叫重构,叫重写。

二,小步走。每一步都是能编译、能过测试的最小改动。一步坏了,你知道是哪个改动引起的。

三,版本控制是朋友。开始前 commit,每成功一步 commit。随时能回退,重构做不下去可以整个放弃,不留后患。

四,测试是必需品。skill 里有句话:"没有测试,你不是在重构,你只是在改代码。" 目标代码没测试,先写特征测试,把当前行为钉住,防止回退。

五,一次只做一件事。重构不跟功能改动混在一起,也不一次重构两件不相干的事。一个 commit 只装一个重构操作。

35.1.2 什么时候不重构

skill 还给了一张反向清单。代码能跑、以后不会再改,别动。关键路径没测试,先补特征测试。赶工期的,把坏味道记下来,以后再改。没有明确收益的,不为了重构而重构。代码方向根本错的,那是重写,不是重构。

35.1.3 实战:重构 IPv6 扩展头

goscapy 加 IPv6 支持时,我让它先重构一段已有的序列化逻辑。

IPv6 头是 40 字节定长。第 4 到 8 字节是 PayloadLength,记录头后面跟了多少字节。这段长度计算散在 ipv6.go 和 ipv6_builder.go 两个文件里,写法还不完全一样。

/refactor 先报坏味道:

然后给重构手法:

最后按五阶段安全协议走:补测试钉住行为,执行重构,验证测试,审查 diff,确认没有行为变更。整个过程不碰功能,只动结构。

35.2 /modern-go:Go 代码现代化

/modern-go 干的是 go fix 的活,再加一批社区公认的现代化规则。它读 go.mod 里的版本,把低于等于这个版本的所有转换规则跑一遍。

35.2.1 按版本门控的规则

skill 里的规则从 Go 1.0 排到 Go 1.27,每一条都标了最低版本。只有项目声明的版本够得着,才套这条规则。比如:

规则总数超过 35 条。版本越高,能套的越多。

35.2.2 语义迁移只报不改

有些规则会改行为,skill 只标成建议,不自动套。math/rand/v2 会换随机数流,固定种子复现结果的项目不能用。iter.Seq 迭代器会重塑 API 形态。os.Root 会改错误路径。这些它指出来,让你自己拍板。

35.2.3 实战:goscapy 升级到 1.26

goscapy 的 go.mod 写的是 1.22。我把 go 指令改成 1.26,再跑 /modern-go。它扫一遍,报出匹配的转换:

跑完它给一张汇总表:文件、套了哪些规则、共改了多少处、哪些规则因为版本不够被跳过。改完每个文件再跑一遍 goimports,把多出来的 import 清掉。

35.3 /insight-diagram:架构可视化

/insight-diagram 读代码库,生成 UML 图、架构图、流程图。它一共支持 17 种图,分两大类:结构性图形管静态结构,行为性图形管交互过程。最后用 /architecture-diagram 渲染成 HTML 加 SVG,存到 docs/ 目录。

35.3.1 十七种图

结构性图形 8 种:系统架构图、类图、对象图、组件图、部署图、包图、复合结构图、剖面图。

行为性图形 9 种:流程图、用例图、活动图、状态机图、序列图、通信图、定时图、交互概览图、泳道图。

最常用的是两个非 UML 的:系统架构图看全局组件关系,流程图看主流程和分支。

35.3.2 先分析,再选择

skill 不直接画。它先读项目:入口文件、子目录的 CLAUDE.md、源码结构、接口定义、依赖注入点。提炼出组件清单、关系图、核心类型、主流程,然后问你画哪几张。

它给的默认推荐是架构图、序列图、流程图三件套。架构图看整体,序列图看关键交互,流程图看流程分支。

35.3.3 实战:goscapy 的架构

我让它分析 goscapy。它扫出 6 个子包、12 个协议层,推荐了四张图:

每张图生成后它跑一个几何校验脚本,查三件事:箭头落点对不对、框有没有重叠、框间距够不够。查出 ERROR 必须修,修完再跑,直到归零。这一步保证了图能看,不会叠成一团。

35.4 /code-to-spec:逆向生成文档

/code-to-spec 反向走一遍。它读一个已经写好的项目,产出一份 SPEC,说清楚这个项目干什么、怎么搭的、对外暴露什么契约。输出是一份活的文档,新成员靠它能上手,重写项目靠它能重建。

35.4.1 十个方面

它扫十个方面:项目身份(README、go.mod、git 历史)、架构、技术栈、功能、数据模型、API 面、配置、外部依赖、测试质量、部署运维。

35.4.2 十二章 SPEC

扫完它合成一份 12 章的 SPEC:项目概述、技术栈、项目结构、数据模型、API 面、配置、外部依赖、业务规则、非功能特性、测试策略、已知缺口、附录。

不是每章都要。项目没有数据库,数据模型那章就省掉。没有部署配置,部署那章也不写。

35.4.3 几条反模式

skill 特别划了几条线,防的是 AI 逆向文档时的老毛病:

35.4.4 实战:给贡献者一份地图

goscapy 想吸引贡献者,但没有一份像样的项目文档。我让 /code-to-spec 扫整个仓库,产出一份 12 章的 SPEC。

最有用的是 API 面那章。它把 Builder API 和 Shortcut 函数逐个列出来:每个函数签名、参数、返回值。新贡献者照着这张表就能看懂两套构造路径的区别,不用自己翻源码猜。

它还在已知缺口里诚实写了一条:IPv6 分片重组还没实现,测试只覆盖了 NS 和 NA 两种 NDP 消息。这句话比任何宣传都实在。

35.5 /note-it:实现笔记

/note-it 在第 8 章出现过,是流水线的倒数第二步:/review-it 之后、/ship-it 之前跑一次。它把实现过程中那些不会写进代码的东西记下来,生成 docs/issue#XXXX.html。

35.5.1 四类记录

笔记分四类:

每一类就算没内容,也要写一句 "None" 说明为什么没有。

35.5.2 实战:IPv6 的决策

goscapy 的 IPv6 实现做完,我让 /note-it 记了一页:

决策一,为什么用自定义 IPv6Addr,不用 net.IP。原因是 net.IP 是 4 或 16 字节的可变长度,序列化时还得判断一次。IPv6 地址固定 16 字节,自定义类型能直接按定长读写,省掉判断。

偏离一,原计划支持全部 NDP 消息类型,实际只实现 NS 和 NA。RS、RA、Redirect 在当前阶段的收益太低,先放下。

待确认一,IPv6 Fragment Header 怎么处理。这件事影响分片重组的设计,得先定下来。

这些内容代码里不会有,spec 里也没有。它记的是"当时为什么这么干",隔半年回来看,价值比注释还高。

35.6 /ship-it:提交交付

/review-it 审完,/note-it 记完,代码还在功能分支上。最后一步是 /ship-it:提交、推送、建 PR、合入、关 Issue,五步跑完。

35.6.1 五步交付

skill 把交付拆成五步,每步有硬性规则。

第一步 commit。只暂存本 Issue 相关的文件,别的变更一律不碰。commit message 必须带 Issue 编号,比如 Add IPv6 extension headers (#42)。以后从 Issue 反查代码,靠的就是这个编号。

第二步推分支。分支名有约定:feat/issue-42-ipv6-ext 这样的格式,Issue 编号直接写在名字里。

第三步建 PR。PR 描述里写 Closes #42。合入后 GitHub 自动关掉这个 Issue,不用人操心。

第四步合入。先跑 gh pr checks,CI 全绿再合。默认 squash merge,整个 Issue 压成一个 commit,历史干净。--delete-branch 顺手把远程分支也删掉。

第五步补实现总结。PR 合入后,在 Issue 上加一条评论:核心变更有哪些、PR 编号、commit hash。以后翻 Issue,一眼就能跳到代码。

35.6.2 出错怎么办

skill 连错误处理都列好了。CI 挂了,修完追加 commit 再推。有冲突,rebase 到最新的 main,解决完 force push。合入被分支保护规则挡住,说明还差 required review,找人 approve。Issue 没被自动关掉,多半是 PR 描述里漏了 Closes #N,手动补一句 gh issue close。

35.6.3 实战:交付 IPv6 支持

goscapy 的 IPv6 扩展头做完,/ship-it 一趟跑完:commit 带上 Issue 编号,PR 描述写清楚实现了哪些扩展头,checks 全绿后 squash 合入,Issue 上留下实现总结。从提交到合入,中间没让人盯过任何一步。

交付这件事最容易被草率带过。commit message 随手写个 update,PR 描述空着,Issue 忘了关,分支留了一堆。/ship-it 把规矩写死在流程里:每一步都是它替你做,每一步都做得规规矩矩。

35.7 /humanize-it:去 AI 味

/humanize-it 管文档的最后一道工序:把 AI 生成的文档改得有人味。它下面挂了三个子 skill,按文档类型挑一个起手,效果不好就换下一个,最多迭代 42 轮。

35.7.1 三个子 skill

技术文档默认先走 technical-writing,通用文章先走 humanizer-zh。

35.7.2 迭代到达标

每改写一轮就打个分,百分制,五档权重:AI 痕迹去除占 30%、自然度 25%、信息完整 20%、风格一致 15%、可读性 10%。过了 80 分就停。没过就换下一个 skill,在上一版基础上继续改。同一个 skill 连续三轮分数不涨,也换。

35.7.3 实战:润色 TECH_SPEC.md

/code-to-spec 生成的 TECH_SPEC.md 我交给 /humanize-it 处理。它先指出问题:additionally、moreover、in conclusion 这类连接词太多,段落结构过于工整,读起来像模板。

然后迭代:第一轮去掉连接词和套话,第二轮把长句拆短,第三轮把评价性的形容词换成具体事实。三轮下来,同一份文档,读起来像是人随手写的,而不是机器吐出来的。

35.8 本章小结

核心技能让代码跑起来,增强技能让代码活得久。两套一起用,工程才算完整。