最后一周都在修它造的 Bug

发布时间:2026/10/27 22:06:05

最后一周都在修它造的 Bug 这是我接手的一个运行了 6 年的 Spring Boot 单体服务核心模块 5000 行最臃肿的那个类 1800 行47 个方法堆在一起没有注释单测覆盖率 8%。前任的前任离职的时候留了一句话“这块别乱动动了必翻车。”我用 Claude Code 开干了。第一周重构进展顺利AI 拆类、提方法、补测试速度确实快。第二周我开始合并代码准备上灰度然后——连续 3 天每天下午收到告警凌晨定位问题根因全是 AI 重构时悄悄改了的东西。AI 代码不会说我不确定它只会自信地告诉你这样完全等价。等你发现不等价可能已经在生产了。这篇文章记录我踩的 4 个真实坑每个坑都有具体的翻车经过和防坑方法。AI重构遗留代码踩坑复盘四大坑与防坑心法图4个核心踩坑的翻车现场与根因分析坑一AI 删掉的死代码其实是 Spring 运行时注入的 Bean这是最隐蔽的坑也是第一个让我上线后翻车的坑。我让 Claude Code 扫描整个服务找出没有被任何地方引用的类删掉它们。AI 给出了一份 37 个候选类的列表自信满满地说这些都是死代码删掉可以减少代码量、降低维护复杂度。我看了几个确实在项目里搜不到任何直接引用。批准删除。上线之后某个异步消息处理功能直接 500。定位了两个小时发现是 OrderNotificationEventListener 这个类被删了。这个类长这样Componentpublic class OrderNotificationEventListener {Autowired private NotificationService notificationService; EventListener public void handleOrderCreated(OrderCreatedEvent event) { notificationService.sendConfirmation(event.getOrderId()); }}项目里没有任何地方写 new OrderNotificationEventListener()也没有 Autowired OrderNotificationEventListener。但它是活的。Spring 的组件扫描会自动把 Component 标注的类注册到容器里。它监听 OrderCreatedEvent只要 Spring 的 ApplicationContext 发布这个事件它就会被调用。没有显式引用只有运行时反射注入。AI 的 grep 分析找不到调用链——因为调用链在运行时才存在。这不是个例。我们那个服务里被误判的类一共 11 个分属以下注解Component、Service、Repository、EventListener、Scheduled、ControllerAdvice。防坑心法给 AI 加一条硬性规则在 prompt 里明确写清楚。规则带有以下注解的类永远不标记为死代码即使找不到显式引用Component, Service, Repository, Controller, RestController,Configuration, Bean, Entity, MappedSuperclass,Scheduled, EventListener, Async, Aspect,ControllerAdvice, RestControllerAdvice,Converter, JsonComponent,以及任何以 *Initializer 结尾的类名。原因Spring 依赖注入是运行时反射机制静态分析无法追踪这类依赖。还有一类更难发现通过字符串动态加载的 Bean。Class.forName(“com.example.OrderService”)、BeanFactory.getBean(“orderService”)这些都是 AI 的死角。凡是字符串拼接类名的地方AI 永远判不准。过去用静态分析工具找死代码的逻辑在这里完全失效——不是工具不够好是 Java 的反射机制本来就是为了绕开静态分析而设计的。坑二上下文窗口到底AI 的函数语义悄悄漂移了第二个坑更难发现因为代码看起来完全正确测试也过了只有特定场景下才会出问题。我在重构的第 8 天让 Claude Code 整理一个 800 行的订单处理核心类把分散的逻辑提取成独立方法。任务很顺利AI 改了 40 多处代码变得整洁多了。三天后上线收到告警某类订单的优惠计算出现偏差。金额差了几块钱不是每笔都有大约每 200 笔里有 1-2 笔。排查到最后发现问题出在这段逻辑AI 在提取某个方法时把一个本来是局部变量的 BigDecimal discountBase 改成了读取 this.orderContext.getDiscountBase()。AI 注释里写的是“等价重构将局部变量替换为 context 字段读取逻辑不变。”逻辑确实一样——在大多数场景下。但问题在于orderContext.getDiscountBase() 在某些分支下返回的是已经应用了会员折扣之后的值而原来的局部变量是在折扣应用之前算的。两者在 95% 的情况下相等只有当订单同时触发多个折扣叠加的时候值才不同。为什么 AI 会犯这种错误这和上下文窗口的工作原理直接相关。会话开始├── 第 1-15 个文件 ← AI 能完整理解上下文├── 第 16-35 个文件 ← 早期细节开始被压缩└── 第 36-45 个文件 ← AI 对前面文件的记忆已经模糊这里的重构开始出现语义漂移当 AI 在处理第 40 个文件里的 OrderProcessor 时它对第 8 个文件里 discountBase 计算时机的记忆已经非常模糊了。它只知道这里用的是 discount basecontext 里也有一个 discount base就做了等价替换。根据 Augment Code 的实测数据在跨 50 个文件总计 200K token 的重构任务中上下文漂移导致约 40% 的任务出现不一致。这不是模型的问题是架构限制。任何当前的 LLM 都面临同样的问题。防坑心法一分批次重构每批控制在 10-15 个文件。每完成一批要求 AI 输出一份语义变更摘要哪些函数的行为发生了变化变化在哪里。这个摘要不需要人工审读每一行但如果某个函数出现在摘要里那就重点 Review。防坑心法二在业务计算函数旁边写注释标明时序依赖。// 注意此处 discountBase 必须在 applyMemberDiscount() 调用之前计算// 如果读取 context.getDiscountBase()在多折扣场景下值会不同// 修改此函数时请检查 DiscountCalculationFlowTest 的时序测试用例BigDecimal discountBase order.getOriginalAmount();这类注释对人类工程师是废话但对 AI 是关键信号。有了它AI 在重构这个函数时会主动保留时序约束而不是等价替换。防坑心法三对金融计算、状态机转换、时序依赖的代码重构后必须跑专项测试。不是测试通过就 OK是要有覆盖多折扣叠加、边界金额、状态切换顺序的专项用例。这类 case 通常不在普通单测里需要专门写。坑三AI 说仅移动代码不改逻辑但它改了这个坑比上面两个更难防因为 AI 主动打破了你给它的限制而且改的是你没让它改的地方。有一次我明确告诉 AI“只重新组织这个文件的包结构不要修改任何实现逻辑不要做任何优化。”AI 回答“明白我只会移动代码不做任何功能变更。”然后它把代码移好了同时删掉了 3 个冗余的局部变量声明把一个三目表达式改成了 Optional 链式调用还把某个日志格式从字符串拼接改成了占位符格式。每一处单独看都是合理的优化。但合在一起有一处改坏了原来的代码是String errorMsg Order orderId failed: reason;log.error(errorMsg);// 注意errorMsg 这个变量后面还被用到了notifySupport(errorMsg);AI 改成了log.error(“Order {} failed: {}”, orderId, reason);notifySupport(Order orderId failed: reason);两处行为一致但 notifySupport 接收的消息和 log 打印的消息现在是两次字符串拼接变成了两个对象。在原来的代码里两者是同一个字符串引用这在某个地方被 比较过是的这是更早的坑所以行为不同了。这类问题的根源在于AI 不理解不要优化这个指令的真实含义。 对 AI 而言把字符串拼接改成占位符格式不叫改逻辑那叫最佳实践。它没有办法区分你的不改逻辑和它理解的不改逻辑。防坑心法用 git diff 做机械检查不要用眼睛。重构完成后用这个命令过滤掉纯格式变化看实质性的代码变更查看所有改动排除纯空白行变化git diff --ignore-all-space HEAD~1重点检查这些类型的变化git diff HEAD~1 | grep “^” | grep -E “(Optional|stream()|lambda|-)”任何你没有明确要求的变更都需要仔细审查。如果 AI 在只移动代码的任务里修改了表达式不管改得对不对都要 Review。另一个方法是在 prompt 里添加行为验证要求任务完成后列出所有你修改的代码行不包括格式调整。如果你修改了任何我没有明确要求修改的逻辑请在报告里标注原因。大多数时候 AI 会老实报告。偶尔它会遗漏但这比完全不报要好得多。坑四AI 生成的数据库迁移脚本开发 2 秒生产锁表 8 分钟这个坑跟 AI 重构的关系不是直接的但是 AI 辅助重构过程中非常容易触发。我们在重构中新增了一个字段 processed_atAI 生成了对应的 Flyway 迁移脚本ALTER TABLE orders ADD COLUMN processed_at DATETIME;UPDATE orders SET processed_at created_at WHERE status ‘COMPLETED’;CREATE INDEX idx_orders_processed_at ON orders(processed_at);在开发环境1000 条数据2 秒跑完完美。到了生产环境orders 表 5200 万行。ALTER TABLE 在 MySQL 5.7 默认加表级锁8 分钟。这 8 分钟里所有涉及 orders 表的写操作全部阻塞。我们的下单服务直接打满P99 超过 30 秒用户侧开始出现超时错误。数据库 DBA 问了一句话我现在还记得“这个脚本你们 review 过大表影响吗”我当时不知道怎么回答。AI 生成的脚本在逻辑上完全正确。它没有做错任何事。但它不知道生产环境的数据量不知道 ALTER TABLE 在大表上的行为也不知道需要用 pt-online-schema-change 或者 MySQL 8.0 的 INSTANT 算法来避免锁表。这类问题在小数据集开发环境里根本不会暴露AI 又无法感知生产数据规模。防坑心法建立数据库迁移的 checklistAI 生成脚本后必须走 checklist。数据库迁移 Review Checklist□ 涉及的表当前行数是多少生产数据□ ALTER TABLE 操作在 MySQL 版本下是否使用行锁还是表锁□ 行数超过 100 万时是否使用 pt-online-schema-change 或 gh-ost□ UPDATE 操作是否有 WHERE 条件批量更新是否分批执行□ 新建索引是否在低峰时段执行□ 这个迁移是否可回滚如果不可回滚已知晓风险对于大表 DDL推荐的命令是使用 pt-online-schema-change100万行以上pt-online-schema-change–alter “ADD COLUMN processed_at DATETIME”–executeDyour_db,torders或者 MySQL 8.0 的 INSTANT 算法仅支持部分 DDLALTER TABLE ordersADD COLUMN processed_at DATETIME,ALGORITHMINSTANT;可以把这个 checklist 直接加到 AI 的 system prompt 里让它每次生成迁移脚本时自动过一遍输出自检结果。不是所有问题都能被它发现但会好很多。这些坑背后的共同原因四个坑表面看原因各不相同但往深里追有一个共同点AI 没有你的系统上下文但它的
延伸阅读

更多相关文章

2026/10/27 22:04:33

嵌入式系统EMIFA SDRAM配置与初始化实战指南

1. 项目概述与核心价值在基于TI C6000系列DSP或类似高性能嵌入式处理器的项目里,外部存储器接口(EMIFA)的配置往往是硬件工程师和底层驱动开发者必须啃下的硬骨头。尤其是当你的系统需要挂载SDRAM(同步动态随机存取存储器&#xf…

2026/10/27 22:03:41

Citrix虚拟化技术核心架构与部署实践

1. Citrix虚拟化技术概述Citrix Virtual Apps and Desktops 7 1912 LTSR是当前企业级虚拟化解决方案中的标杆产品。作为长期服务版本(Long Term Service Release),它为企业提供了稳定可靠的应用程序和桌面虚拟化平台。我在金融行业实施这个方…

2026/10/27 18:06:59

07-使用案例集

Dify 使用案例集(可复刻实战) 适用版本:Dify Community Edition v1.16.0 面向读者:零基础,已完成前 6 篇 阅读时长:约 40 分钟 前置:04、05、06 目标:照着做,独立复刻 6 …

2026/10/27 22:01:38

Nmap网络扫描核心技术解析与实战应用

1. Nmap网络扫描技术全景解析 Nmap作为网络探测和安全审计领域的瑞士军刀,其核心价值在于通过主动探测技术揭示网络设备的真实状态。我第一次接触Nmap是在一次企业内网渗透测试中,当时用 nmap -sS -T4 192.168.1.0/24 这个简单的命令就发现了三台存在高…

2026/10/27 22:01:38

MySQL GROUP BY与COUNT高效统计状态数据详解

1. 项目概述 在日常数据库操作中,统计不同状态的数据记录数量是最基础也是最频繁的需求之一。作为一名长期与MySQL打交道的开发者,我发现很多新手在面对这类统计需求时,往往会写出效率低下甚至错误的SQL语句。今天我们就来深入探讨如何正确使…

2026/10/27 22:01:38

光纤传感器原理与类型:物性型vs结构型核心差异解析

简介:本资源是一份面向电子、测控、光电类专业学生及工程技术人员的光纤传感器基础原理图解资料,聚焦物性型与结构型两大分类及其核心工作机制,解决对光纤传感技术物理本质与典型应用理解不深的问题。文档以图文结合方式系统阐述温度、压力、…

2026/10/27 22:01:38

i2 Analyst‘s Notebook 8 实战指南:从话单导入到司法级图谱分析

简介:本资源是一份面向安全分析、金融风控及刑侦调查从业者的i2 Analysts Notebook 8专业培训教材,聚焦话单挖掘、银行交易追踪、案件串并与人员动态关系建模等实战场景,帮助初学者系统掌握IBM这款主流图谱分析工具的核心能力。文档为单文件W…

2026/10/27 22:01:38

数据库ANY权限的安全风险与最佳实践

1. 数据库权限管理中的"ANY权限"解析 在数据库安全管理领域,ANY权限(如GRANT SELECT ANY TABLE)是一种特殊类型的系统权限,它允许被授权者对数据库中所有对象(包括当前和未来创建的对象)执行特定…

2026/10/27 21:56:38

GraphQL批量查询攻击防护与优化实践

1. 当GraphQL批量查询成为攻击者的新武器 第一次在生产环境遇到GraphQL批量查询攻击时,我正盯着监控面板上突然飙升的CPU曲线发愣。那是一个看似平常的API请求,却在短短几秒内触发了数十个关联查询,导致数据库连接池瞬间耗尽。这种攻击不像传…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑