代码卫生六步清扫:用AI技能系统治理代码库

发布时间:2026/10/13 9:03:57
代码卫生六步清扫:用AI技能系统治理代码库
代码卫生这件事说起来不大做起来真磨人。我自己的项目里经常是功能能跑就先跑等回头要加需求或者排查线上问题的时候面对一堆历史代码那种想清又不敢清的憋屈感估计写代码超过三年的人都懂。后来我把这套清理动作整理成一个可复用的技能包起了个名字叫Hygiene-sweep也就是标题里说的代码卫生六步清扫.skill。我之所以强调是skill而不是脚本或者检查清单是因为现在主流的 AI 编程助手基本都支持自定义技能把一套标准动作写进技能文件再配合仓库里的真实代码做上下文判断比我以前开十几个终端窗口人肉排查要稳得多。而且这套东西不挑语言只要是工程级代码库基本都能用。这篇文章就把这条 skill 从设计思路、六步内容、落地过程到踩坑记录完整拆给你看。1. 代码卫生为什么要做成一条 skill而不是临时想起来扫一遍1.1 代码卫生到底在扫什么先说个真实场景。有一回我接手一个老服务功能是正常的但每次部署我都提心吊胆因为根本不知道哪条 import 是没用的、哪个分支永远不会被执行、哪段注释已经和代码事实完全相反。后来我花了一个下午人肉扫了一遍累倒是不怕问题是扫完才发现自己用的还是凭感觉那一套根本没有形成可复用的标准。代码卫生不是一个抽象概念它其实可以被拆成几个非常具体的检查面依赖卫生有没有锁文件里躺着十几个不用的包有没有明知有 CVE 还一直拖着的版本。结构卫生有没有 Copy-Paste 出来的几百行重复代码有没有一层套一层的包目录。表达式卫生有没有一眼看不懂的魔法数字、又臭又长的 if 嵌套、根本没用的常量。信息卫生有没有把数据库连接串、密钥、内部域名直接写死在代码里。流程卫生有没有吞掉异常的 catch、打满日志却全是 INFO 噪音的打印、缺了兜底分支的网络调用。验证卫生有没有那种测试跑过了但断言形同虚设的假测试有没有改了业务代码测试却完全没响应的死角。这六类问题单看每一个都不致命但叠在一起就是线上事故和迭代变慢的温床。所以我把它们编排成一条固定的清扫流水线让 AI 助手每次照着同一套流程去扫而不是靠程序员当天的心情。1.2 为什么是六步而不是一份普通检查清单很多人会说这不就是一份 checklist 吗把它写成文档贴进 Wiki 不也一样差别很大。普通 checkList 是给人看的你得自己逐条对照然后手动去找代码、改代码、验证改完的结果而 skill 是给人模型工具这个组合体执行的。拿我用的方式来说一条 skill 通常包含三个部分指令定义告诉模型这个技能要干什么、按什么流程走、规则上下文把什么是脏代码的定义给模型让它照着标准判断、可执行动作调用 grep、ast 解析、依赖审计等命令去仓库里捞真实线索。说白了就是我先当那个把经验沉淀成标准动作的人然后让模型在我的标准里做苦力活。六步的设计也不是随手拍脑袋。它有一个很关键的递进关系前两步先扫能不能跑得干净依赖、死代码中间两步扫人能不能看得懂命名、信息泄露风险最后两步扫出了问题能不能兜得住日志异常、测试闭环。从运行层面到维护层面再到风险层面一层一层往深里走实际上模拟的是一个有经验的老开发拿到陌生代码库时的自然动作先看工程配置再看代码结构然后翻业务逻辑最后确认测试。2. Hygiene-sweep 六步清扫的整体设计与思路拆解2.1 第一步清扫依赖与构建链路这一步我把它放在最前理由是依赖问题连锁反应最大。一个过期的传递依赖可能在某个冷门接口上给你埋雷一个删不掉的死依赖则会让镜像体积无缘无故大出几百兆。具体操作上我会让 skill 先做三件事列全量依赖清单锁定文件和实际 import 清单做差集再看安全公告。差集这一步尤其重要很多项目里package.json写了 50 个包实际代码里只用了 20 个剩下 30 个纯粹是历史惯性留下来的。把差集列出来标成建议移除但注意不要自动删因为有些包是构建脚本、代码生成器在用的直接删会炸。实际操作里我最满意的工具组合是Python 项目用pip-audit查已知漏洞Node 项目用npm audit同时不管什么语言都把requirements.txt、Pipfile.lock、package-lock.json这类文件翻一遍。特别提醒一句别只盯着直接依赖npm audit报的很多问题都在传递依赖里这时候要看升级方案而不是一刀切升级盲升大版本带来的破坏往往比漏洞本身更难受。2.2 第二步清扫死代码、重复代码与坏味道死代码是那种看着活着、其实没人调用的东西。老项目里最常见的死代码有三种被注释掉的旧逻辑块、导出了却从来没人 import 的函数、以及被硬编码条件挡住的永久不可达分支。这一步的清扫逻辑是反着来的先让 skill 建立引用关系图然后找那些出度为 0 的节点。简单说就是一个函数如果有定义、有导出但整个仓库里搜不到任何调用点那它基本就是死代码候选。像 VSCode 里搜全局、IDEA 里的 Find Usages都能干这件事但问题是没法批量出报告。用 skill 的好处是可以让模型去把所有候选结果汇总成一张待人工确认表格每条附上文件路径、定义行号、最后一次 git 修改时间方便我快速决定是删还是留。重复代码的识别就更直接了用简单的文本哈希或者 AST 对比都能做。但我要给个实用建议重复三处以内先别急着抽公共函数强行抽象在业务变化快的时候反而难维护。skill 在这一步真正该标记的是那种五行逻辑复制了七八遍中间只改了一个参数的高危重复这才是抽函数、抽配置的最佳候选。2.3 第三步清扫命名、注释与可读性命名问题我以前觉得不重要直到有一次我 debug 一个线上问题发现变量叫temp2另一个叫temp3而temp早就被注释掉了。从那以后我把命名列为固定清扫项。这一轮的标准其实很朴素不看注释能不能读懂这段代码在干什么。skill 会专门挑出那些含义模糊的命名比如单字母变量、带数字后缀的变量data1、data2、一个词干到底的函数名handle、process、doWork然后结合上下文给出更具体的替代名。举例来说handle出现在订单模块里替代名可能是handleRefundTimeout出现在营销模块里可能就应该是handleCouponExpiry。注释这块我会让模型盯住两类一类是和代码矛盾的错误注释这类必须改因为它会误导后来者另一类是代码本身丑到需要注释解释的场景这时候正确的做法不是补注释而是把代码重构到不需要注释也能看明白。关于可读性我建议加入一个很主观但有效的指标单函数行数和嵌套深度。超过 80 行的函数、嵌套超过 4 层的 if清扫报告里必须出现。不用急着让模型重写先标出来标得多了自然会发现哪些模块最该重构。2.4 第四步清扫安全与敏感信息安全清扫在六步里最不能省但也最需要控制噪音。这一步我会让 skill 分两条线走一条是硬编码敏感信息另一条是高风险接口的误用。硬编码敏感信息靠正则就能扫掉一大半类似AKIA开头的访问密钥、password 后面跟字符串、Bearer后面贴 token、jdbc:mysql://连接串里带明文密码还有提交到 Git 历史里的.env文件。特别提醒.git 历史里的泄露比当前代码里更隐蔽GitHub 上那些密钥泄露事故多数是删了文件但没清历史。所以我会让 skill 在清扫时顺带检查最近 50 条提交里有没有新增的敏感文件。高风险接口的误用稍微难一点但模型做初步筛选完全够了。比如不校验输入就直接拼 SQL、把用户可控参数传进文件路径、在循环里执行加解密操作。这些不一定是漏洞但至少是值得人工复审一次的代码位置。我把这轮标记为审查点而不是必须改避免清扫变成一场狼来了的闹剧。2.5 第五步清扫日志、异常与错误处理日志和错误处理是代码卫生里最脏也最容易被忽略的部分。我见过很典型的一个服务平时日志量巨大但真出了事排查的人根本无从下手因为满屏全是INFO: step 1 done、INFO: step 2 done唯一的ERROR还是something went wrong。这一轮清扫我会重点看三件事第一异常吞没。空catch块、catch 住了只打一行 debug 日志不往上抛的全部拉出来示众。第二日志能不能支撑事后复盘。关键业务入口、外部接口调用、数据库操作这些位置必须有带上下文信息的日志光有save failed等于没写。第三错误码和错误信息是否可检索。理想状态下每个明确的错误分支都应该有唯一标识方便在日志系统里直接按标识搜。我还额外加了一条很个人化的规则警惕字符串拼接日志。日志框架的懒加载是有意义的用字符串拼接会无条件执行拼接操作在高频路径上会有性能损耗这属于看不见的脏。这一类问题模型很容易发现标记出来改成占位符写法就行。2.6 第六步清扫测试闭环与可观测性最后一步很多人会漏掉但我觉得恰恰是代码卫生和代码整洁的区别所在。代码整洁是静态的好看代码卫生是动态的健康——一个功能能不能改完就放心上线取决于测试有没有兜住。测试闭环的清扫分三个层次有没有测核心业务模块有没有对应的单元测试或集成测试文件。真不真测试文件里有没有形同虚设的断言。比如只断言返回不为空不校验具体结果或者断言写死了 Mock 数据压根没测到真实逻辑。同步性git 历史里某几个模块频繁改动但对应测试文件的改动次数远低于业务代码说明这些模块正在失去保护。可观测性这部分我扫的是指标和链路。有没有给关键接口加耗时统计有没有把错误率暴露成监控指标这部分不像前五步那样能机器化地一刀切所以我把它设计成生成建议清单的模式让模型把哪些模块快裸奔了标出来剩下的人工去排优先级。3. 实操落地从零配置一个 Hygiene-sweep skill3.1 skill 文件结构与最小的可运行骨架不管你是用 Claude 系的 SKILL.md还是其他支持自定义技能的编程助手底层逻辑都差不多给模型一份带明确流程的 markdown 文件让它知道现在该用什么样的身份、按什么样的步骤、调用什么样的命令来处理问题。我习惯的最小骨架长这样# Hygiene-sweep 实现一个专门的代码卫生检查流程对目标仓库执行六步清扫。 每次扫描必须以结构化报告形式输出结果。 ## 技能说明 - 适用场景接手陌生项目 / 发版前自查 / 代码评审预检 - 输出语言与项目代码注释语言保持一致默认中文 - 扫描范围排除 node_modules、dist、build、.git 等目录 ## 执行流程 1. 先扫描项目根目录识别语言类型与包管理工具 2. 按六步清扫顺序逐项检查 3. 每步输出问题清单标注文件路径、行号、严重程度 4. 合并结果生成最终报告注意看这个文件里我只写了流程框架没有写具体的什么是脏的标准。标准必须单独放否则文件会很臃肿模型也不容易记住重点。我会用类似下面的 YAML 片段把规则外置让主文件保持清爽rules: dead_code: - 导出却无引用的函数 - 被注释掉的完整逻辑块 - 条件判断中永假的半支 sensitive_info: - AKIA[0-9A-Z]{16} 类型的访问密钥 - 明文密码赋值 - 嵌入代码的数据库连接串3.2 六步清扫指令模板的核心写法六步的指令写法我这里直接给出我调试到还算稳定的版本。每一步都包含三个元素目标描述、可执行动作、输出格式要求。以第一步为例### Step 1: 依赖与构建链路清扫 目标识别依赖声明与实际使用不一致的包识别存在安全公告的版本。 执行动作 - 读取锁文件package-lock.json / Pipfile.lock / go.sum / pom.xml - 结合源码目录的 import 语句生成未使用依赖列表 - 若本机具备安全审计工具npm audit / pip-audit执行并记录结果 输出要求 - 未使用依赖列表按体积或引用数排序标注建议移除或谨慎保留 - 安全风险列表标注 CVE 编号、影响版本、建议升级目标 - 不要自动修改 manifest 文件只输出修改建议其他五步的写法和这个完全同构只是把目标、动作、输出换成对应的清扫主题。这种统一的结构对我特别有用模型在跑的时候不会迷路我拿回报告的时候也知道每部分该怎么读。有一点必须强调所有指令里都要写明不要自动修改。因为代码清扫这件事最大的风险不是扫不到而是模型自作主张帮你改了一堆你以为它是对的结果破坏了某个隐式约定。我在早期版本里踩过这个坑后来所有动作默认只输出报告只有拿到报告、人工确认之后才允许进入下一步修复模式。3.3 与真实工具链的绑定指令写得再漂亮最终还是要落到真实命令行工具上。我在 skill 里绑定的工具清单大概是这样用途工具说明Python 依赖审计pip-audit直接依赖和传递依赖的 CVE 检查Node 依赖审计npm audit输出 JSON 格式方便解析死代码扫描vulture/knip/ 自定义 grep 组合按项目语言选重复代码检测jscpd支持多语言直接标重复率敏感信息搜索trufflehog/gitleaks扫描当前文件和历史提交测试覆盖率对照pytest --cov/jest --coverage拿数据和 git 修改频率做交叉验证但是不是所有人都装了这些工具所以我给 skill 加了一条降级策略如果执行环境里没有对应命令就用模型自带的代码阅读能力去扫同时把未安装工具记进报告备注。这样无论环境多简陋技能都不会直接罢工。实际跑一轮的效果我很满意模型会把每个工具的原始输出先汇总、再过滤、再标注严重级别。比如npm audit一次能吐几十条里面绝大多数是低危的传递依赖直接展示价值不大。skill 会把这些按是否有修复路径是否影响直接依赖是否被主流程调用三层过滤最终汇报里只留几条真正要人做决策的。3.4 一次真实清扫的输入与输出对比这是我目前看到的最直观的效果展示。有一次我拿一个已经有两年多没做技术债清理的后端仓库做测试仓库不算大四十多个 Python 文件加三个入口脚本。传统人肉扫的话我估计要半天到一天用这条 skill 跑整个过程大概十几分钟包括模型阅读上下文的时间。输出报告的关键摘要长这样依赖层面发现 3 个只出现在 requirements.txt 却从未被 import 的包其中 1 个已经维护状态不明。死代码层面12 个无引用函数共涉及约 900 行代码6 段被注释掉的旧逻辑块最早注释时间跨度两年。信息卫生层面发现 1 个明文的 Redis 密码、2 个疑似 AWS 密钥字样的字符串以及 1 份误提交的.env文件。错误处理层面17 个空 catch 块集中在文件上传和支付回调两处。测试同步性业务代码两个文件的 git 提交次数超过 60但对应测试文件的提交不到 5 次。拿到这个报告我第一反应是有点丢人第二反应是踏实。因为所有这些以前都藏在我感觉好像没什么问题的盲区里。更重要的是报告不是模型拍脑袋编的每条都附了路径、行号、引用关系我可以直接点过去验证。4. 常见问题与排查技巧实录4.1 权限报错SKILL 读取文件时提示 setNamedSecurityInfo failed这个坑我遇到过而且特别典型。有的 skill 平台在 Windows 环境下执行时会尝试调整文件权限或继承安全属性如果当前终端进程没有管理员权限就会冒出来一行类似setnamedsecurityinfow failed (win32)的报错。排查思路很简单分三步走先分清是读不了还是改不了。如果是读取阶段就报错大概率是平台配置里给了 skill 太高的权限请求如果是写报告阶段报错那就是输出目录的 ACL 有问题。把 skill 的输出目录从系统盘临时目录挪到当前用户目录下很多权限问题是 Windows 的路径保护策略导致的。如果还不行就用icacls手动给工作目录加当前用户的写权限或者直接换一个纯用户态的目录当工作区。我的建议是不要为了省事全局给启动器管理员权限图一时方便后面 skill 版本迭代时权限边界会越来越难收敛。把这个报错当成环境治理的信号反而能逼你把目录权限理顺。4.2 大仓库扫描导致上下文爆掉代码卫生技能最怕的就是超大仓库。一次扫描读几百个文件命令输出几十万行模型上下文直接红温轻则报告质量下降重则平台直接拒绝继续执行。我的处置经验是给 skill 加采样模式和全量模式两个档位。采样模式适用于第一次接触的巨型仓库按目录树抽样每个主要模块挑 2-3 个代表性文件加上锁文件和全局配置文件先跑一轮粗扫。输出的是风险热力图哪个目录问题密度高、哪类问题占比大。这样你不需要把全仓库喂给模型也能快速定位重灾区。全量模式只适合中小仓库或者已经采样之后的定向深扫。真要在超大仓库里做全量清扫我会先把待扫描范围切割成模块级任务一次只扫一个模块最后在报告层面合并。多跑几次比一次硬塞进去的效果稳得多。4.3 误报太多如何区分真实问题与噪音清扫技能刚跑通的时候我差点被误报劝退。最典型的误报有两种一种是把第三方库的代码当成项目死代码因为扫描范围没排干净另一种是把刻意保留的兼容代码标记成该删比如为了兼容老版本字符串格式特意保留的解析分支。处理误报我的办法是给 skill 加了三层过滤路径黑名单把非业务目录site-packages、node_modules、vendor、build彻底排除出问题扫描只在统计背景信息时引用。模式白名单在规则里增加跳过已知合理模式比如支付回调里的空 catch 如果有注释说明就不要当作异常。置信度分级建议输出结果的时候分成高置信建议修改中等置信需要人工确认仅作为提示信息三档这样不会被几十条噪音淹没有效信息。三层过滤下来有效信息比例提升非常明显。我现在看一眼报告开头那张分级汇总表就能判断今天要不要安排一次清扫。4.4 清扫结果如何沉淀成团队规范最后一个值得聊的问题是清扫报告看完了问题也修了然后呢如果每次都靠一条 skill 扫完就完事代码卫生永远停留在事后救火状态不会真正改善。我的做法是把 skill 的输出格式往提交规范上靠。具体就是让报告末尾自动生成三条沉淀建议哪些问题应该加进 CI 的检查脚本比如硬编码密钥的正则扫描、必须通过依赖审计的硬门槛。哪些模块的测试覆盖率需要补直接生成一个补测优先级列表。哪些命名和注释模式要在评审规范里明令禁止比如禁用temp1这类无意义命名。这样每次清扫不只是清一次垃圾而是给项目留下一套越来越厚的护城河。我用这个思路跑了一个季度最明显的变化是仓库的技术债增长速率慢下来了因为规则一旦写进 CI 和评审规范新代码在进门的时候就被拦掉了一大截。5. 写在最后的一点个人体会这条 Hygiene-sweep skill 前前后后迭代了四个版本从最初只有一句帮我检查代码质量问题到现在完整覆盖六步清扫流程我最深的体会是代码卫生的价值不在于一次性把仓库收拾得多干净而在于它把什么是脏、怎么算干净这件事定义出来了让整个团队在同一个标准下协作。个人开发者用它能在接手旧项目时快速建立全局风险认知小团队用它可以在评审前多一道机器预检在更大的组织里它甚至可以作为技术债治理的自动化底稿。如果你也想做一条类似的 skill我的建议是别一上来就追求大而全先聚焦你最痛的那一类问题。比如你被线上密钥泄露搞怕过就先把敏感信息扫描做到极致你被屎山代码坑过就先把死代码和重复代码的识别做好。一个够用的 skill永远好过一个追求完美结果却根本跑不起来的 skill。还有个小技巧值得分享skill 里的规则标准不要闭门造车直接从你最近三次手写代码评审记录里提炼。你现实中真正会挑出来的问题才是技能里最该有的规则通用文档里的最佳实践很多时候落到具体业务场景根本不好使。希望这条六步清扫的经验能帮你的代码库少一点陈年污垢。代码卫生这事打扫一次不难难的是每次都按同一个标准打扫而 skill 恰好让后者变成了一件可以自动执行的事。