一、接手这个烂摊子事情的起因很简单公司有一套跑了三年多的内部审批流后端服务基于 Spring Boot 构建负责处理员工请假、报销、采购等十几种审批场景。系统能跑但没人敢动。接手之后我打开代码第一感受是窒息——ApprovalController单个文件将近 4000 行ApprovalService更夸张超过 8000 行。整个文件从头到尾几乎没有一行注释方法名是doApprove、doApprove2、doApproveNew、doApproveV2Final这种风格。没有任何单元测试上线全靠手动点页面验。我需要在两周内完成重构同时保证线上服务不中断。正常情况下光是读懂这堆代码就要花掉将近一周更别说重写了。我决定把 Claude Code 拉进来——Anthropic 出的命令行 AI 编程工具可以直接在终端里操作项目文件。技术栈情况框架Spring Boot 2.7 MyBatis-Plus数据库MySQL 8.0构建工具Maven代码规模11 个核心模块约 3.2 万行代码二、Claude Code 真正能干活的地方用下来有三个场景它真的让我眼前一亮。场景一读懂旧代码秒出注释和文档第一步不是重写是先搞清楚这堆代码到底在干什么。我把ApprovalService里最核心的审批状态流转方法丢给 Claude Code让它先生成 Javadoc 注释请为以下 Java 方法添加完整的 Javadoc 注释 说明方法用途、每个参数的含义、返回值、 以及可能抛出的异常。不要修改任何业务逻辑。[粘贴代码]输出质量出乎意料地高。原来这个方法我读了二十分钟没完全搞明白Claude Code 生成的注释把状态流转逻辑描述得清清楚楚。当然有两个参数的描述有点偏但整体八成以上可以直接用。改写前无注释publicBooleandoApprove(Longid,Integerstatus,Stringremark,LongoperatorId){ApprovalRecordrecordapprovalMapper.selectById(id);if(recordnull||record.getStatus()!1)returnfalse;record.setStatus(status);record.setRemark(remark);record.setOperatorId(operatorId);record.setUpdateTime(newDate());approvalMapper.updateById(record);if(status2){notifyService.sendApproved(record);}elseif(status3){notifyService.sendRejected(record);}returntrue;}Claude Code 生成注释后/** * 执行审批操作更新审批记录状态并触发对应通知。 * * p仅当审批记录处于「待审批」状态status1时操作才会生效。 * 审批通过status2将触发审批通过通知 * 审批拒绝status3将触发审批拒绝通知。/p * * param id 审批记录唯一ID * param status 目标状态2-通过3-拒绝 * param remark 审批备注允许为空 * param operatorId 执行审批操作的用户ID * return 操作是否成功记录不存在或状态不为待审批时返回 false */publicBooleandoApprove(Longid,Integerstatus,Stringremark,LongoperatorId){// ... 原有逻辑不变}这一步帮我节省了大量读代码猜意图的时间整个模块的文档注释覆盖一天不到全部完成。场景二重复性重构十几个 if-else 变策略模式这套审批系统支持十几种审批类型原来的实现方式是一个巨大的if-else链if(LEAVE.equals(type)){// 请假审批逻辑约200行}elseif(EXPENSE.equals(type)){// 报销审批逻辑约180行}elseif(PURCHASE.equals(type)){// 采购审批逻辑约230行}// ... 还有十几个分支整个processApproval方法超过 1500 行。让 Claude Code 把它重构为策略模式它给出的结构非常清晰// 策略接口publicinterfaceApprovalStrategy{StringgetType();ApprovalResultprocess(ApprovalContextcontext);}// 各审批类型实现类Claude Code 自动生成骨架ComponentpublicclassLeaveApprovalStrategyimplementsApprovalStrategy{OverridepublicStringgetType(){returnLEAVE;}OverridepublicApprovalResultprocess(ApprovalContextcontext){// 原有请假逻辑迁移至此}}// Context 统一调度ServicepublicclassApprovalStrategyContext{privatefinalMapString,ApprovalStrategystrategyMap;publicApprovalStrategyContext(ListApprovalStrategystrategies){this.strategyMapstrategies.stream().collect(Collectors.toMap(ApprovalStrategy::getType,s-s));}publicApprovalResultprocess(Stringtype,ApprovalContextcontext){ApprovalStrategystrategystrategyMap.get(type);if(strategynull)thrownewUnsupportedApprovalTypeException(type);returnstrategy.process(context);}}原来 1500 行的怪物方法拆成了 14 个职责单一的策略类。每个类单独维护新增审批类型只需加一个实现不再动核心逻辑。场景三单元测试从 0 到 60%重构之前这个项目的单元测试覆盖率是 0%。让 Claude Code 针对核心 Service 方法生成 JUnit5 Mockito 用例ExtendWith(MockitoExtension.class)classApprovalServiceTest{MockprivateApprovalMapperapprovalMapper;MockprivateNotifyServicenotifyService;InjectMocksprivateApprovalServiceapprovalService;TestvoiddoApprove_shouldReturnFalse_whenRecordNotFound(){when(approvalMapper.selectById(anyLong())).thenReturn(null);BooleanresultapprovalService.doApprove(1L,2,ok,100L);assertFalse(result);verify(notifyService,never()).sendApproved(any());}TestvoiddoApprove_shouldNotify_whenApproved(){ApprovalRecordrecordnewApprovalRecord();record.setStatus(1);when(approvalMapper.selectById(1L)).thenReturn(record);approvalService.doApprove(1L,2,approved,100L);verify(notifyService).sendApproved(record);}}两天内核心模块测试覆盖率从 0% 提升到约 62%。三、踩坑实录Claude Code 让我栽跟头的 5 件事当然不是什么都顺利。这 5 个坑希望能帮你少走弯路。坑1它引用了一个不存在的方法重构ApprovalRecord的工具类时Claude Code 生成了这样一行StringnormalizedRemarkStringUtils.trimAllWhitespaceAndNormalize(remark);我当时以为是 Spring 的StringUtils里的方法版本可能不对查了半天 Maven 依赖升了一次 Spring 版本还是报NoSuchMethodError。最后去翻源码才发现这个方法根本不存在。是 Claude Code 自己造出来的名字听起来非常像官方 API但实际上从未存在过。教训所有 AI 生成的外部方法调用必须逐一到源码或官方文档里核实。“看起来像不等于确实有”。坑2上下文一长就开始断片当我把整个ApprovalService约 8000 行一次性丢给它处理时它在重构后半段把前面已经定义好的ApprovalContext类给忘了开始用ApprovalDTO、ApprovalRequest等各种不一致的命名生成的代码根本无法编译。教训长文件必须拆开处理每次只投喂一个方法或一个类。我后来的习惯是每次上下文不超过 300 行效果稳定很多。坑3业务逻辑它根本不懂审批系统里有一段会签逻辑多个审批人必须全部通过审批才能流转到下一节点但如果某个审批人的级别达到 L5 以上可以直接一票通过。Claude Code 生成的代码把这两个条件的判断顺序写反了——先判断了全员通过再判断 L5 特权导致 L5 审批人一票通过的逻辑永远不会触发。代码读起来完全没问题逻辑也很流畅但业务跑起来就是不对。这个 bug 在测试环节才被发现险些上线。教训凡是和具体业务规则强绑定的核心逻辑不能直接用 AI 生成结果只能让它提供框架逻辑本身必须自己写或逐行审查。坑4测试用例只测快乐路径Claude Code 自动生成的测试用例几乎清一色是正常输入、正常返回的场景。边界条件——比如审批人 ID 为 null、审批记录已被其他人操作导致的并发冲突、会签场景下中途有人撤回——基本没有覆盖。这些场景我后来自己补了将近 40 个测试用例。教训AI 生成测试用例之后必须自己列出边界清单逐一补充。把异常场景描述清楚告诉它它也能生成但得你主动去问。坑5有一段代码我没看懂却通过了 ReviewClaude Code 用了一段比较巧妙的CompletableFuture链来优化并行通知逻辑。代码写得很优雅同事 Review 时也说没问题我觉得应该没问题就合入了。一周后压测时发现在高并发场景下这段逻辑存在线程池耗尽的风险。回头再细看才发现它用的是默认的ForkJoinPool没有做任何线程池隔离。教训如果你自己看不懂 AI 生成的代码就不应该合入。理解是你的责任不是 AI 的。四、我总结的人机协作分工边界用下来我大概总结出了这张表任务类型建议做法原因添加注释 / 生成文档✅ 完全交给 AI不涉及逻辑风险低省时间重复性重构消除重复代码✅ 完全交给 AI有固定模式AI 擅长样板代码DTO、Builder、测试框架✅ 完全交给 AI规律性强几乎无需修改单元测试用例⚠️ AI 生成 人工补边界正常路径 OK边界需人工补充外部 API 调用 / 第三方依赖⚠️ 必须人工验证幻觉风险高容易引用不存在的方法核心业务逻辑❌ 只做参考不直接使用AI 不理解业务上下文架构决策❌ 不要交给 AI需要全局视野和业务判断并发 / 安全相关代码❌ 必须人工实现风险太高不容出错五、最终结果重构耗时从预估的两周缩短到约 9 天其中 Claude Code 帮我节省了大约 3 天的时间主要集中在注释生成、样板代码和测试用例初稿上。核心数据代码行数从 3.2 万行压缩到约 1.9 万行删除了大量重复逻辑单元测试覆盖率从 0% 提升到约 62%上线后首两周线上 Bug 数比历史同期减少了约 60%六、个人判断Claude Code 确实让我提效了但它没有让我变成一个更好的程序员——那部分还得靠自己。它更像一个很快、不知疲倦、但偶尔会一本正经说错话的实习生。你得知道什么能交给他做、做完要检查哪里而不是直接合并他的 PR。AI 编程工具的价值在于把你从重复性劳动里解放出来让你把精力放在真正需要判断力的地方。但判断力本身还是你自己的事。最后问一句你们在用 AI 编程工具重构项目时遇到过什么更离谱的坑评论区见。本文为个人原创实战记录首发于 CSDN。