代码正在腐烂?用Claude Code重构,将技术债转化为技术资产

0 阅读23分钟

凌晨两点多,我盯着那个让我头疼了一个月的项目。

这就是那种典型的"屎山"——不是谁故意写的,就是时间久了,需求改来改去,人来人往,紧急上线加功能,修 bug 补丁打补丁,最后变成了一坨没人敢动的代码。

我给项目起了个名字叫"老三"——这是我们团队维护的订单系统的第三个版本,也是目前唯一还在跑的版本。前两个版本早就废弃了,老三撑到现在,也快撑不住了。

老三为什么会烂

说起来老三一开始不这样。

半年前我刚接手的时候,它还挺干净的。标准的 MVC 分层,接口文档写得也算完整,单元测试覆盖率 70%以上——在当时已经算不错了。

问题出在三个地方。

第一个是需求

产品经理每次都说"这个功能下周一定要上",而且每次都说得特别好,特别紧急。但我们都知道,这些需求都没有长远考虑,全是短期方案——能快速上线就行,后面再说。第一个月加了个"限时优惠",我直接在 controller 里加了 if-else 。第二个月说"那个用户场景要支持",我又在 service 里塞了两个新方法。第三个月运营说"紧急 bug ,今晚必须修",我写了个补丁直接改了数据库字段。

三个月后,老三开始变味了。

第二个是不同的人

这半年里,项目里来了走、走了来,至少换了 4 个开发者。有的喜欢用 Stream API ,有的就爱写 for 循环;有的热衷设计模式,有的觉得"能跑就行";有的命名规范是驼峰,有的偏爱下划线。你想想,四种风格、四种水平混在一起,代码能不乱吗?

有一天我看着一个 150 行的 controller 方法,里面嵌套了 8 层 if-else ,变量命名一会儿驼峰一会儿下划线,注释写的全是"TODO: 需要重构"——我就知道,完了。

第三个是设计跟不上

老三最初的架构设计是好的,但那只是针对半年前的需求规模。现在用户量翻了几倍,业务场景复杂了十倍,原来的设计已经撑不住了。每次加新功能都要在旧架构上打补丁,越打越多,越补越厚。就好比你住的是个两居室,非要硬塞进四口人还能住吗?能,但就是挤得慌,哪哪都不舒服。

但我当时没管。你想啊,功能还能跑,用户没抱怨,紧急需求又压着,谁有闲时间去重构?

技术债的利息

老三开始吃我的时间了。

最明显的是改一个小 bug 要花三倍时间——因为你不知道改这里会不会影响别的地方。而且你也不敢确定这个 bug 是谁引入的,是三个月前走的那个实习生?还是上个月接手的外包?代码里连个像样的 git commit message 都没有,全是"fix bug"、"紧急修复"这种鬼话。

每次上线前要 regression test 至少两小时,因为你根本不信任代码的稳定性。你也知道,测试用例覆盖不全,有些边界条件根本没人测过,但也没人敢加——加了又怕把原来能跑的 case 给弄坏了。

最要命的是,新需求越来越难加。

上个月产品说要加个"批量导出"的功能,我看了三天代码,发现要改的地方散落在 7 个文件里,改任何一个都可能炸。而且这 7 个文件是 4 个不同的人写的,代码风格完全不一样——有的用 Lombok ,有的手写 getter/setter ;有的用 Optional ,有的直接判 null ;有的异常往上抛,有的自己吞了。

我跟产品说"这个功能开发周期要两周",产品说"为什么?不就是加个导出按钮吗?"

我没法解释。

你怎么解释"虽然功能看起来简单,但代码结构已经烂了,不同人写的代码风格不一样,原来的架构设计已经撑不住了,我要先重构才能加新功能"这种话?听起来像在找借口。


进退两难

那段时间我真的很纠结。

一方面,老三已经烂到这个地步了,你想逐步迭代?不可能。每次改一点都像拆炸弹——你不知道这个 if-else 背后还连着什么,你不知道改了这个方法会不会把别的地方的流程给断了。渐进式重构的前提是代码结构还清晰,但现在老三的代码结构早就面目全非了。

另一方面,重写?老三现在有几十个功能模块,几百个接口,上千个业务场景。重写需要多少人日?三个月?半年?这还不算测试、联调、上线。而且,重写意味着要有一个非常全的功能测试 case 覆盖所有场景——你敢保证你不会漏掉任何一个边缘场景吗?漏掉一个,上线就是事故。

我当时就跟领导说:「老三这项目,现在是个死结。逐步重构推不动,全部重写成本太高。我看不到出路。」

领导说:「你想想办法。」

我想了一周,实在想不到办法。

遇到 Claude Code

大概三周前,我在朋友圈刷到有人在用 Claude Code 重构项目。

说实话我一开始没太在意。你想啊, AI 写代码这种事, ChatGPT 刚出来的时候我就试过,生成的代码能用但不够"人类"——风格跟我项目里的代码格格不入,改起来比从头写还麻烦。

但那天老三又出 bug 了——一个简单的逻辑错误,我找了 4 个小时没找到原因。

凌晨一点多,我躺在沙发上,手机里刷着 Claude Code 的文档。

文档里有一句话让我停住了:

"Claude Code 不是帮你写新代码的,是帮你理解现有代码、重构现有代码的。它会先花时间'读'你的项目,理解你的设计模式和业务逻辑,然后再给你建议。"

这句话戳中我了。

我就是那种"我的代码只有我懂"的人。每次新人进团队,我都得花一周时间教他怎么读老三。现在有 AI 愿意花时间理解我的代码?我决定试试。

第一次对话

安装很顺利, VS Code 里装个插件,登录一下就 OK 了。

我打开老三的项目,在右侧面板里输入:

帮我分析这个项目的技术债务,重点是代码复杂度、重复代码、依赖耦合 

Claude Code 没有立刻给我答案。它先显示了:

正在扫描项目... 分析了 127 个文件 识别了 34 个类、 289 个方法 构建了调用关系图...

这个过程花了大概两分钟。两分钟后,它给了我一个报告:

技术债务评估

代码复杂度 - 平均圈复杂度: 8.7 (建议≤6 ) - 最复杂方法: OrderController.placeOrder(),圈复杂度 21 - 超过建议值的方法: 47 个( 16.2%)

重复代码 - 重复代码块: 32 个 - 重复代码行数: 1247 行 - 重复率: 9.3%(建议≤5%)

依赖耦合 - 循环依赖: 3 处 - 过度耦合: OrderService 依赖了 15 个类 - 违反单一职责原则的类: 9 个

优先级建议

P0 (立即处理)  1. OrderController.placeOrder() 方法重构(圈复杂度 21 ) 2. 消除 OrderService 的过度耦合(依赖 15 个类)

P1 (本周处理)  1. 重构 32 个重复代码块 2. 修复 3 处循环依赖

P2 (本月处理)  1. 优化其他高复杂度方法 2. 建立代码规范和自动化检查

我看完报告,心里五味杂陈。

一方面,这些数据印证了我之前的判断——老三确实烂了。另一方面,它比我想象的还要糟。圈复杂度 21 的那个方法,我居然就是"写"的那个人——现在想想,当时怎么就敢写成那样?

重写计划

Claude Code 给了我一个完整的重写策略——不是修修补补,是重新理解、重新设计、重新实现。

阶段 1 :功能梳理与测试覆盖( 2-3 天)

"既然要重写,首先要确保我知道这个系统到底有哪些功能。"

Claude Code 先让我列出系统的所有功能模块和测试方法。它不是要我写一份需求文档,而是要我通过以下方式梳理:

1.运行现有系统,记录每个功能入口、输入输出、异常场景2.查看现有测试用例(如果有的话),分析覆盖范围3.跟产品、运营、测试沟通,补充那些没有文档化的业务规则4.生成一份功能清单,每个功能都包含:场景描述、输入、输出、边界条件、异常处理

它说:「这一步不是走形式。重写最怕的是『漏功能』——上线后用户说『原来还有这个功能啊』,那就尴尬了。」

阶段 2 :代码架构梳理( 3-5 天)

"代码量太大,我无法一次性全部读进去。让我先有个全局视角。"

Claude Code 给出了一个关键策略——生成Code Map(代码地图):

1.整体架构扫描:识别系统的分层、模块划分、核心流程2.依赖关系分析:画出模块间的调用关系图3.拆分梳理系统分母:把系统拆分成若干个子系统,每个子系统独立可理解4.补充系统文档:    - 结合已有的技术文档(如果有)    - 让 Claude Code 阅读代码、理解逻辑,生成缺失的设计文档    - 补充数据模型、接口定义、业务流程图

它说:「这样分步骤的好处是,我不会被几万行代码淹没。我逐个模块理解,最终拼出完整的系统全貌。」

阶段 3 :逐步重写与验证(核心阶段, 2-4 周)

「现在我知道这个系统是干什么的、怎么设计的了。我们可以开始重写了。」

Claude Code 给出了重写的核心流程——实现到测试、验证的闭环

使用 OpenSpec/Speckit Skill 生成代码:    - 基于阶段 2 梳理的系统设计文档    - 逐个子系统生成规范化的代码    - 遵循统一的编码规范和设计模式

边实现边验证:    - 每完成一个子系统,立即运行对应的测试用例    - 对比重写前后的功能行为,确保一致    - 如果测试失败, Claude Code 会分析原因、修复代码、重新测试

持续集成:    - 每个子系统验证通过后,集成到主系统    - 运行端到端测试,确保子系统间协作正常    - 记录测试结果,生成测试报告

它说:「这个闭环流程的关键是『小步快跑』——不要等全部写完再测试,而是写一点测一点。这样问题能及时发现,不会堆积到最后。」

阶段 4 :质量门禁与上线( 1-2 天)

1.代码质量检查:配置 SonarQube ,确保代码质量指标达标2.性能测试:对比重写前后的性能,确保没有退步3.灰度发布:小范围灰度,观察线上表现4.全量上线:确认无误后,全量切换

我看了一眼日历,周五晚上。这个计划看起来至少要 4-6 周——比我想象的要长,但比完全人工重写(估计要 3-6 个月)还是要快很多。

开始重写:第一阶段

我决定先从阶段 1 开始——功能梳理与测试覆盖。

Claude Code 打开了老三的项目,开始扫描所有代码文件。它不是简单地读取每一行代码,而是在建立「代码地图」:

> 正在扫描项目结构... 
> 识别了 15 个模块:用户、订单、支付、库存、优惠券、物流... 
> 每个模块包含:Controller、Service、Repository、Entity、DTO 
> 构建模块间调用关系图... 
> 识别核心业务流程:下单、支付、发货、退款... 

然后它问我:

我看到了代码的结构,但我需要确认一些事情:  
1. 这个系统有没有现成的功能清单或需求文档? 
2. 现有测试用例覆盖了多少功能? 
3. 哪些业务规则是隐式的(没有写在代码注释里,需要跟业务方确认)? 

我愣了一下。隐式业务规则?我想了想——是啊,老三里确实有很多「潜规则」:比如用户下单后 30 分钟内取消不扣优惠券,比如 VIP 用户的订单优先处理,比如周末的订单不自动确认收货……这些规则有的写在了代码的 if-else 里,有的干脆就是产品经理口头说的,根本没文档。

Claude Code 说:「这些隐式规则如果梳理不清,重写出来就会漏功能。你帮我列一份,我会把它们都变成显式的规则。」

我花了两天时间,跟产品、运营、测试一一确认,终于列出了老三的所有功能清单——一共 87 个功能点,每个都包含了场景描述、输入输出、边界条件、异常处理。

Claude Code 看完清单,说:「好的,现在我理解了这个系统是干什么的了。下一步,我要梳理代码架构。」

代码架构梳理完成

花了 5 天时间, Claude Code 完成了代码架构梳理。它生成了一份完整的系统设计文档:

系统分母( 5 个子系统)  1. 订单中心:下单、支付、取消、退款 2. 用户中心:注册、登录、权限、 VIP 体系 3. 商品中心:商品管理、库存、分类、搜索 4. 营销中心:优惠券、活动、推荐 5. 运营中心:数据统计、日志、监控

每个子系统的设计文档包含: - 数据模型( Entity 、 DTO ) - 接口定义( Controller ) - 业务逻辑( Service ) - 数据访问( Repository ) - 调用关系图 - 异常处理策略

Claude Code 说:「现在我对这个系统的理解,比写它的人还要清楚了。我们可以开始重写了。」


逐步重写:第一个子系统

Claude Code 建议从「订单中心」开始——这是老三的核心,也是复杂度最高的部分。

它使用了 OpenSpec/Speckit Skill ,生成了订单中心的代码:

// OrderController - 下单接口 
@PostMapping("/orders")
public Result<OrderVO> placeOrder(@RequestBody PlaceOrderRequest request) {
    // 1. 参数校验
    validateRequest(request);
    
    // 2. 调用服务层
    Order order = orderService.placeOrder(request);
    
    // 3. 返回结果
    return Result.success(OrderVO.from(order));
}

// OrderService - 下单业务逻辑
@Service
public class OrderService {

    public Order placeOrder(PlaceOrderRequest request) {
    
        // 验证订单
        validateOrder(request);
        
        // 计算价格
        PriceInfo priceInfo = calculatePrice(request);
        
        // 检查库存
        checkInventory(request.getItems());
        
        // 处理支付
        PaymentResult paymentResult = paymentService.processPayment(request, priceInfo);
        
        // 创建订单
        Order order = createOrder(request, priceInfo, paymentResult);
        
        // 发送通知
        notificationService.sendOrderCreated(order);
        
        // 更新库存
        inventoryService.decreaseStock(order.getItems());
        
        return order;
    }
    
    // ... 其他方法
}

我看了下代码,发现几个惊喜:

1.代码风格统一:所有方法都遵循同一个规范,没有「有的用 Stream 有的用 for 循环」这种混乱2.职责清晰:每个方法只做一件事,没有那种 150 行的巨无霸方法3.异常处理规范:所有异常都有明确的类型和错误码4.注释完整:每个方法都有清晰的 JavaDoc ,解释了业务逻辑

最让我意外的是——它居然把那些隐式业务规则都显式地写出来了:

// 用户下单后30分钟内取消不扣优惠券
if (order.getCancelTime() != null && 
    ChronoUnit.MINUTES.between(order.getCreateTime(), order.getCancelTime()) < 30) {
    couponService.returnCoupon(order.getCouponId());
}

// VIP用户的订单优先处理
if (user.isVip()) {
    order.setPriority(OrderPriority.HIGH);
}

效果验证:边写边测

Claude Code 的重写流程有个关键特点——边实现边验证

订单中心的代码生成后,它没有继续生成其他子系统的代码,而是先跑测试:

> 运行订单中心测试用例... 
> 测试用例数量:23 个 
> 通过:21 个 
> 失败:2 个  
> 失败用例: 
> 1. testCancelOrderWithin30Minutes - 优惠券未被退回 
> 2. testVipOrderPriority - VIP订单未被设置高优先级 

它自动分析了失败原因:

> 分析失败原因... 
> 用例1:取消订单的时间判断逻辑有误 
> 用例2:VIP判断条件未正确实现  
> 正在修复... 
> 修复完成  
> 重新运行测试... 
> 全部通过 ✓ 

我看着这个过程,心里想:这不就是我想做但一直没时间做的事吗?每次改完代码跑测试、发现 bug 、分析原因、修复、再测试——如果人工做这个过程,可能要花一整天。但 Claude Code 只用了 5 分钟。

但我心里有个疑问。

Code Review :人不能退场

虽然 Claude Code 的自动测试很厉害,但我们团队还是做了分批多次的 Code Review——不是一次 review 所有代码,而是每个子系统写完就 review 一次。

为什么?

第一个原因是失控感

如果代码完全掌握在 AI 上,没有人知道具体系统的代码实现,那种失控感是很可怕的。你不知道 AI 生成的某个方法会不会在某种边界条件下出问题,你不知道某个异常处理是不是考虑了所有场景,你不知道某个性能优化会不会在数据量大的时候崩了。

这种「不知道」不是「不重要」,而是「无法承担后果」。

第二个原因是责任归属

只有人才真正会对系统负责。

如果系统出了问题——比如订单丢了、优惠券扣错了、用户数据泄露了——你不能说「这是 AI 写的,我不负责」。用户不会找 AI ,他会找你们公司。法律不会审判 AI ,它会审判你们公司。老板不会开除 AI ,他会开除你。

AI 无法担责。

所以我们必须通过 Code Review ,确保每一个 AI 生成的代码都有人理解、有人把关、有人负责。

但这里有个很现实的问题——

现在整个行业都在灌输「未来会替换掉那些不会使用 AI 的人」,企业似乎「既要又要」:既要 AI 提高效率,又要人对系统负责。但问题是,如果你完全依赖 AI ,你就失去了对系统的掌控;如果你要掌控系统,你就不能完全依赖 AI 。

这中间的平衡点在哪里?

我的答案是——人不能退场,但人可以换个方式在场

以前的人在场是「写每一行代码」,现在的人在场是「理解每一行代码、审查每一行代码、对每一行代码负责」。 Claude Code 负责生成,我负责理解、审查、负责。

这听起来像是在给 AI 当「监工」,但其实是——

AI 让我从「代码搬运工」变成了「代码架构师」和「代码审查员」。我不再纠结每一行代码怎么写,而是关心整体架构是否合理、业务逻辑是否正确、边界条件是否考虑周全。

这其实是升级,不是降级。

当然,这是我的理解。我也不知道对不对。

给企业决策者的警告

写到这里,我想给那些看到 AI 的惊艳表现、正在考虑「降本增效」的企业决策者说几句。我知道你们在看这篇文章——不管是 CTO 、技术总监,还是 CEO 、老板。

现在市面上有很多内容在灌输焦虑:「程序员要被淘汰了」「一人开发一人设计」「全栈才是未来」。这些内容背后,很多是在卖课。卖课没问题,但问题在于——很多课程的质量真的就一般,甚至很低。

更重要的是,这些焦虑内容会让人失去理性判断。

我想问你们几个问题:

你们的历史代码、历史项目,真的能被 AI 接管吗

老三重写花了 5 周时间——这是一个已经在运行的系统,有明确的需求、有现成的测试用例、有我可以问的产品经理和运营。而且,老三只有 5 个子系统、 87 个功能点。

如果你的系统已经跑了 5 年、 10 年,有几十个子系统、上千个功能点,而且需求文档早就丢了、写代码的人早就走了、测试用例覆盖率不到 30%——你觉得 AI 能接管吗?

我告诉你答案:不能。

AI 需要「理解」才能「重写」,但如果你的系统本身就没有「可理解性」, AI 也无能为力。垃圾进,垃圾出。

你们真的能直接降本增效吗

老三重写前,团队有 5 个开发人员。重写后,我们还是 5 个人。

为什么?因为 AI 生成的代码需要人去理解、审查、负责。如果把开发人员裁掉一半,剩下的人能 cover 住 Code Review 的工作量吗?不能。

而且, AI 不是免费的。 Claude Code 的使用成本、 OpenSpec/Speckit 的授权费用、测试环境的资源成本——这些都要算进去。我算了一下,老三重写的 AI 成本,大概相当于 3 个开发人员一个月的工资。

如果是为了省钱, AI 可能反而更贵。

你们要把全员转全栈吗?把焦虑传递给打工人

我见过有的公司,因为 AI 能写前端代码,就逼着后端开发学前端;因为 AI 能写后端代码,就逼着前端开发学后端。美其名曰「全栈工程师」,实则是把公司的焦虑传递给打工人。

但问题是——全栈不是「什么都会一点」,全栈是「在某个领域很深,在其他领域能够沟通」。逼着一个后端开发去写前端 Vue 页面,他写出来的东西,大概率不如一个专业的前端开发。

AI 能写代码,但 AI 写不出「用户体验」, AI 写不出「交互细节」, AI 写不出「性能优化」。这些还是需要人来。

千万不要在还没完整构建出可行的 AI 产线的情况下,就大面积启用 AI 去替换大量的人工

这是危险警告。

老三重写成功了,是因为我们: 1. 有明确的系统边界和功能清单 2. 有完整的测试用例覆盖 3. 有分批次的 Code Review 机制 4. 有能够理解系统、承担责任的人

如果没有这些, AI 重写就是灾难。

我听说有的公司,看了几个 AI 工具的 demo ,就决定裁员 50%,把剩下的开发逼着学 AI 工具。结果三个月后——系统上线 bug 满天飞,新功能开发速度不升反降,开发人员集体离职,公司不得不重新招人。

这不是降本增效,这是自杀。

企业家要有自己的思考,不要被焦虑内容牵着鼻子走。

真正的价值

一个月后,老三完成了重写——5 个子系统, 87 个功能点,全部用新代码实现。

但变化不止是代码。

新人小张进团队了

按照以前的习惯,我得花一周时间教他怎么读老三的代码。但这次不一样,我把系统设计文档发给他,说:「你先看这个,不懂的问我。」

小张看了半天,跟我说:「师兄,这个系统的设计文档比我以前见过的任何项目都清晰。我看了一遍,大概就知道每个模块是干什么的了。」

他花了一周时间熟悉系统,第二周就能开始写新功能了。以前要一个月。

产品经理来提需求了

以前产品提需求,我得先想半天——这个功能要改哪些文件?会不会影响其他功能?测试要多久?

现在不一样。我打开系统设计文档,找到对应的模块,跟产品说:「这个功能属于订单中心,我可以在这个 Service 里加一个方法,预计 2 天完成。」

产品经理愣了一下,说:「这么快?以前类似的都要一周啊。」

我说:「因为代码结构清晰了,加功能就像搭积木一样——你知道哪块积木该放在哪。」

测试同事来提 bug 了

以前测试提 bug ,我要花半天时间定位——这个 bug 在哪个文件的哪一行?是谁写的?为什么这么写?

现在不一样。测试说「用户下单后优惠券没扣减」,我直接打开 OrderService 的 placeOrder 方法,看了几行代码,就知道问题在哪了——第 45 行,优惠券扣减的逻辑放在了支付成功之后,但支付可能异步,所以有时候会漏掉。

修复? 10 分钟。

但最让我感动的不是这些。

技术债→技术资产

老三重写完成了。

变化是系统性的:

开发效率提升 - 新功能开发时间从平均 5 天缩短到 2 天 - Bug 修复时间从平均 4 小时缩短到 30 分钟 - 新人上手时间从 1 周缩短到 3 天

代码质量提升 - 平均圈复杂度从 8.7 降到 4.2 - 重复代码率从 9.3%降到 0.8% - 单元测试覆盖率从 70%提升到 92% - 技术债务指数从 85 分降到 42 分(健康线以下)

系统可维护性提升 - 每个子系统独立可理解、可测试、可部署 - 系统设计文档完整,新人 3 天上手 - 代码风格统一,不再有「四种风格混在一起」的问题 - 架构设计清晰,能支撑未来 2-3 年的业务增长

团队信心提升 - 大家不再怕改老三的代码了 - 技术债不再是「死结」,而是「可以管理的东西」 - 重写不是「额外工作」,而是「投资」——现在每次加新功能,都比以前快

但我最想说的是——

技术债不是「罪」,它是软件开发的必然。快速交付需要权衡,有些债是值得借的。关键不是「不借债」,而是「借了要知道怎么还」。

Claude Code 帮我把那些「我不敢动的代码」变成了「我可以管理的资产」。它不是魔法,它只是给了我一个工具——一个帮我理解复杂系统、梳理架构设计、逐步重写验证的框架。

写在最后

重写老三花了 5 周时间——比我预期的要长,但比完全人工重写(估计要 6 个月)还是要快很多。

更重要的是,我学到了一件事:

当系统烂到一定程度时,渐进式重构已经不可能了。你必须承认——这个系统需要重写。但重写的成本太高怎么办?

AI 是一个选项。

它不是完美的,它会犯错,需要你 review ,需要你调整。但它能做到人类做不到的事情:

1.快速理解海量代码——几万行代码,它花 5 天就能梳理清楚架构2.不遗忘的细节——隐式业务规则、边缘场景,它都能记录在案3.边写边测的闭环——写一点测一点,问题及时发现4.统一的代码风格——不会出现「四种风格混在一起」的问题

代码和城市一样,会熵增、会腐化。重构不是「完美主义」,是「可持续发展」。

我不指望老三永远不烂——那不现实。但现在,我有了一个工具,能让我在它开始烂的时候,更早发现、更快处理。

这就够了。

嗯。