Vibe Coding 死代码删除证明:没有搜索结果为什么还不够
静态工具报 unused、文本搜索为零或覆盖率没命中,都不能单独证明代码不可达。本文组合入口清单、引用分析、运行证据、历史 owner 与分阶段撤除,降低误删动态调用风险。
本文要点
- 主题聚焦:Vibe Coding、AI Agent、TypeScript、开源
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
删除代码通常比新增代码更容易通过审阅:diff 变小、构建更快,AI 还能给出“全仓库没有引用”的自信结论。但插件名、路由字符串、配置键、模板、反射、定时任务、命令行入口和仓库外消费者都可能绕过普通文本引用。不存在的证据很难被完全证明,因此可信删除依赖多种独立信号,并公开剩余盲区。
先定义删除对象和边界。它是一个私有局部变量、导出函数、包、HTTP 路由、消息消费者、数据库列,还是运维脚本?层级越靠外,所需证据越强。TypeScript 的 noUnusedLocals 会报告未读取的局部声明,但它不证明一个公开导出没有动态或外部消费者。把编译器警告直接翻译成“可安全删除”是类别错误。
从所有入口反向建立可达性
使用编程 Agent 的仓库地图列出 Web 路由、CLI、worker、cron、队列 topic、插件注册、配置加载、测试夹具和生成入口。再用仓库依赖图驱动改动规划计算静态调用者,同时搜索符号、文件路径、导出名、路由字符串、配置键、事件名与大小写变体。搜索命令、范围、忽略规则和 HEAD 都写入证明,不能只贴“0 matches”。
检查无法由普通引用图覆盖的机制:动态 import()、字符串索引、依赖注入容器、装饰器扫描、反射、模板拼接、序列化类型名、feature 配置、外部 webhook、运维 runbook 和客户脚本。对 monorepo 还要查发布包的下游仓库与 registry 使用;对公开 API,调用量为零也要遵守弃用承诺。未知消费者保持 UNKNOWN,而不是因为无权限搜索就当作不存在。
测试覆盖是补充证据。Node Test Runner 可收集覆盖率,但“测试没执行”只说明当前测试集没有走到该代码,既可能是死代码,也可能是测试缺口。生产或 Staging 运行遥测可以观察真实入口,但采样、季节性、租户差异和低频灾备路径会造成假零。证明记录必须写时间窗、流量覆盖、采样策略和已知未观测场景。
组合至少四类独立证据
第一类是结构证据:静态引用、导出图、构建入口和注册表均无活跃边。第二类是行为证据:代表性测试与运行窗口没有命中,同时关键任务有正向覆盖,证明观测系统确实工作。第三类是契约证据:API、消息、配置和数据 schema 中没有仍受支持的合同,或弃用窗口已经完成。第四类是所有权证据:代码 owner、调用方和运维负责人确认没有仓库外用途。
Git log 可以追踪文件和字符串的历史变更,帮助找到最后使用场景、引入原因和熟悉该路径的人;历史久远不是删除理由,最近没改也不代表没运行。若注释写着“兼容旧客户”,要找到客户迁移证据,而不是让 AI 判断注释看起来过时。设计系统这类跨仓库 API 的完整撤除流程可参考组件弃用迁移。
每项信号都记录结论和局限。静态零引用但动态注册未知,状态仍是 BLOCKED;生产零命中但只观察工作日一周,灾备路径仍未知;owner 批准但遥测损坏,也不能继续。只有独立证据共同收敛,才从“疑似未使用”升级为“批准撤除”。
分阶段撤除而不是一次清空
先阻止新引用:在 lint、边界测试或注册表中将目标标为 deprecated/forbidden,并给现有调用清单设水位。随后移除入口注册或把内部流量导向明确拒绝路径,保留短观察窗和恢复方式。确认没有未知调用后,再删除实现、测试 fixture、配置、文档和监控。数据库字段、公开包和事件合同需要更长的兼容阶段,不能套用私有函数的节奏。
撤除探针必须可区分“无人调用”和“观测断了”。例如每个仍到达旧入口的请求增加有界计数与 owner 告警,同时用合成调用证明计数器可见。出现一次未知真实调用就停止删除,恢复入口或隔离调用者,不通过忽略日志继续推进。删除后的候选运行编程 Agent 的测试影响分析选择的回归,并由编程 Agent 的改动验证门绑定最终 diff。
最终删除证明包含对象身份、搜索与图谱范围、动态入口清单、测试/运行观测窗口、外部消费者确认、弃用状态、恢复动作、批准 owner 和剩余风险。它不声称数学上证明任何未来调用都不存在,而是说明在已声明边界内,哪些独立证据支持删除,哪些未知已被接受。Vibe Coding 可以加速盘点和清理,删除权仍应由证据覆盖面决定,而不是由模型搜索速度决定。
延伸阅读
Related