我让AI review了自己写的代码,然后删掉了30%

上周,我做了一件有点羞耻的事。

把自己写了4年的一个核心服务,让AI做了一次完整的Code Review。

结果AI给我列了一张清单。

我看了大概10分钟,关掉了文档,去倒了杯水,回来,删掉了30%的代码。

不是因为代码有bug。

功能一直是正常的,线上跑了4年,没出过任何问题。

是因为AI让我看到了一些东西,我自己已经看不见了。


一、为什么我要做这件事

这个服务是我4年前搭的,核心是处理支付和费用计算的逻辑。

刚写的时候,我很认真。注释清楚,结构分明,自认为写得很好。

然后它就这样跑了4年。

偶尔加个功能,改个字段,但整体结构没人动过。因为"能跑",因为"没空",因为"改了万一出问题"。

上个月,产品提了一个新需求,要在这个服务里加一个费用分摊的逻辑。我打开代码,看了半个小时,发现自己有点看不进去了。

不是代码太复杂,而是太熟悉了。

每一行我都认识,但我已经不记得它们为什么这么写了。

那一刻我意识到:我对这份代码的感情,已经妨碍了我客观地评估它。

于是我做了一个决定:把它交给AI看一遍。


二、我怎么让AI做Review

很多人让AI review代码,用的是这种Prompt:

复制代码
帮我review一下这段代码

然后AI给你一大段泛泛的夸奖加一两条无关痛痒的建议。

没用。

我用的是一个拆分了5个维度的Prompt模板:

复制代码
请对以下代码做Code Review,按照这5个维度逐一分析:

1. 潜在bug(空指针、并发风险、边界条件)
2. 安全风险(注入漏洞、越权、敏感信息泄露)
3. 性能问题(N+1查询、大对象、不必要的重复计算)
4. 可维护性(类职责是否单一、耦合度、扩展性)
5. 代码质量(命名、注释、复杂度)

对每个问题:
- 指出具体的类名和行号
- 说明为什么是问题
- 给出具体的修复建议
- 标注严重程度:严重 / 中 / 低

[粘贴代码]

维度拆分是关键。

不加维度约束,AI会给你一个"综合感受";加了维度,AI会逐项审查,漏掉问题的概率大幅降低。

我把核心的3个类,大概1200行代码,分3次喂给AI,每次一个类。

然后我把AI的清单整理出来,开始逐条看。


三、AI发现了什么

发现1:一个存在4年的潜在NPE

AI标注的第一个问题,严重程度:严重

java 复制代码
// FeeCalculationService.java 第43行
public BigDecimal calculateFee(Order order) {
    return order.getItems().stream()
        .map(item -> item.getPrice().multiply(
            new BigDecimal(item.getQuantity())))
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}

AI的分析:

order.getItems() 未做null检查。若订单明细为空列表,stream正常返回ZERO,但若getItems()本身返回null,将在.stream()处抛出NullPointerException。 同理,item.getPrice() 若为null,.multiply()将直接抛出NullPointerException。 建议在方法入口处添加参数校验,或使用Optional包装可能为null的返回值。

我看完,第一反应是:这个方法跑了4年没出过问题啊。

但我知道AI说得对。

正常业务数据不会有null,但如果有一天做数据迁移,或者清理历史数据,或者某个上游服务异常返回了空对象------这个方法就会爆。

4年没出问题,不代表不是问题。只是运气好。

这是我自己看不见的那种问题。不是因为我技术不行,而是因为我太熟悉这段代码了,每次看到它,脑子会自动补全"这里没问题"。

修复很简单,两行校验的事。但发现它,需要一双没有先入之见的眼睛。


发现2:一个我以为很优雅的设计,其实是自我感动

这个发现让我沉默了更久。

AI标注的第二个问题,严重程度:

复制代码
PaymentStrategyFactory.java      -- 工厂类
PaymentStrategy.java             -- 策略接口
WechatPaymentStrategy.java       -- 微信实现
AlipaymentStrategy.java          -- 支付宝实现
AbstractPaymentTemplate.java     -- 模板抽象类
PaymentContext.java               -- 上下文类

共6个类,合计约460行

AI的分析:

当前系统中支付方式共2种,模板方法模式、策略模式和工厂模式三层叠加, 引入了约340行的抽象代码。这些扩展点在过去4年内从未被使用过。 建议评估是否真的需要这一层抽象。若近期无新增支付方式的计划, 可以简化为一个PaymentService类加if-else判断,约100行, 等真正需要扩展时再重构,代码的可读性和维护成本都会更低。

我坐在那里,盯着这段分析看了很久。

这6个类是4年前我刚学完《设计模式》之后写的。

当时我觉得自己写得很漂亮。策略模式、工厂模式、模板方法,全用上了,还互相配合,简直教科书级别。

写完之后还给同事讲解过,他们说:"哇,这个设计很完整。"

但AI说的是真相:这不是优雅,这是用复杂度证明自己懂设计模式。

4年过去了,从来没有第三种支付方式出现过,从来没有人动过那3个抽象层,那340行代码唯一的作用就是让新来的同事读代码时多花半个小时。

我删掉了这5个类,合并成了1个PaymentService,120行。

功能完全一致,单元测试全部通过。

删完之后,心里有点空,又有点轻松。


发现3:一个真实的安全漏洞

这个是我最后悔的。

AI标注的第三个问题,严重程度:严重

java 复制代码
// ReportQueryService.java 第112行
public List<FeeRecord> queryByCondition(QueryRequest request) {
    String sql = "SELECT * FROM fee_record WHERE merchant_id = " 
        + request.getMerchantId()
        + " AND status = '" + request.getStatus() + "'";
    return jdbcTemplate.query(sql, new FeeRecordRowMapper());
}

AI的分析:

request.getStatus() 直接拼接进SQL,存在SQL注入风险。 若用户传入 ' OR '1'='1 这样的参数,可以绕过status条件查询所有记录。 建议改用参数化查询:

java 复制代码
String sql = "SELECT * FROM fee_record WHERE merchant_id = ? AND status = ?";
return jdbcTemplate.query(sql, new FeeRecordRowMapper(), 
    request.getMerchantId(), request.getStatus());

这个方法,是3年前一个下午赶时间写的。

当时用的是MyBatis-Plus,这个方法是个例外,临时用的jdbcTemplate,一直没人改。

功能上没问题,所以没人注意到。

但这是一个真实存在的SQL注入漏洞,在生产环境跑了3年。

修复是5分钟的事。

但发现它的,是AI,不是我。


发现4:一个AI说错了的建议(这个很重要)

AI的建议不全是对的。

在分析性能问题时,AI给出了这样一条:

RiskControlService.getRiskLevel() 在每次计算费用时都会调用, 建议加入本地缓存(如Caffeine),设置5分钟过期, 可以减少约80%的重复调用,提升性能。

这个建议,我没有采纳。

因为这个接口返回的是实时风控等级,由风控团队根据用户行为动态更新。

5分钟的缓存,意味着风控规则的变更最多延迟5分钟生效。在我们的业务场景里,这5分钟的延迟可能导致资损。

这条上下文,在代码里没有注释,在文档里也没有记录,只存在于我和风控团队两年前的一次对接会议里。

AI不知道。它只看到了"重复调用",看不到"为什么必须实时"。

这是AI做Review必然存在的盲区:它理解代码,但不理解代码背后的业务决策。


四、删掉30%之后

把AI的清单过了一遍,修复了能修复的,拒绝了不合适的,最终结果:

复制代码
修改前:1240行
修改后:860行
删减比例:31%

修复严重问题:2处(NPE风险 + SQL注入)
删除过度设计:340行(支付策略三层抽象)
清理冗余注释和死代码:约40行

单元测试:全部通过
功能:完全一致

代码变少了,但我对它的信心变高了。


然后我问自己一个问题:为什么这些问题,我自己4年都没有发现?

答案是3个字:太熟了。

熟悉带来了3种盲区:

第一种,熟悉度遮蔽。 自己写的代码,大脑会自动补全"应该没问题"的判断,看代码时其实是在"回忆",而不是在"审查"。NPE那个问题我看过这段代码上百次,每次都跳过了。

第二种,沉没成本。 那6个类花了我好几天时间,还讲解给同事看过,删掉等于承认它们是多余的。人不愿意承认自己做了无用功,会本能地为它辩护。

第三种,没有外部压力。 能跑、没bug、没投诉,就没有动力主动审视。所有人都在向前跑,没人回头看。

AI没有这3种包袱。

它不认识我,不知道这段代码我写了多久,不知道我当年对那个设计有多得意。

它只看代码本身。

这是它作为Review者的最大优势。


五、3个实操建议

做完这次Review,我想给你3个具体的建议。

第一,用分维度的Prompt,不要用泛问。

不要说"帮我review这段代码",而是明确列出你想检查的维度:bug、安全、性能、可维护性。维度越清晰,AI给出的问题越具体,越有价值。

完整的Prompt模板,在文章末尾,回复「review」获取。

第二,定期给老代码做一次AI Review,不只是新代码。

新代码你还有印象,自己review相对有效。老代码才是盲区的重灾区------能跑、没人动、谁都不想碰,恰恰是问题最容易藏身的地方。

建议每季度挑一个"能跑但没人动"的模块,专门做一次AI Review。

第三,AI的建议要过滤,重点找它不懂的地方。

AI不知道你们公司的业务规则,不知道某个"看起来可以优化"的调用背后是否有特殊约束。它给的建议里,有10-20%可能不适合你的场景。

过滤本身也是有价值的------它逼你重新想清楚"这段代码为什么这么写"。

如果你能回答这个问题,很好,在注释里写下来。

如果你回答不上来,那可能真的值得改了。


写在最后

12年写代码,我以为我很了解自己的代码。

AI用20分钟告诉我:你只是习惯了它,不等于你真的看清楚了它。

人会对自己写的代码产生感情。

AI不会。

这是它的局限,也是它的价值。


回过头来看,那个SQL注入漏洞让我反思了很久。

它在生产跑了3年。

不是我不懂SQL注入,不是我不知道参数化查询。

是因为那天下午很赶,写完跑通就提交了,后来再也没有人仔细看过它。

这样的代码,在每个人的项目里都有。

你有多久没有认真看一眼自己写的老代码了?


你有没有试过让AI review自己的代码?发现了什么?欢迎评论区聊聊。


后端AI实验室 不讲概念,只谈实战 代码开源,每周更新

相关推荐
_oP_i2 小时前
Dify大模型节点中「系统提示词」和「用户提示词」的区别
ai
SunnyDays10112 小时前
Java 实战:将 Word 文档高效转换为多页 TIFF 图片(含批量处理)
java·word转tiff
一直都在5722 小时前
Java基础面经(二)
java·开发语言
银发控、2 小时前
record类
java·开发语言
jiayong232 小时前
可视化流程设计器技术对比:钉钉风格 vs BPMN
java·前端·钉钉
左左右右左右摇晃2 小时前
MyBatis & MyBatis-Plus 面试题整理
java·笔记
xiaoye37082 小时前
CentOS 7 搭建Maven私服
java·maven
北极糊的狐2 小时前
MySQL常见报错分析及解决方案总结(42)---ERROR 1142 (42000): SELECT command denied
java·mysql·adb·myeclipse