我把同一个需求分别交给初级程序员、高级程序员和AI,结果让我沉默了

上个月,我们有个新功能要做:实现一个订单退款接口

需求不复杂,但涉及金额变更、库存回滚、状态流转,刚好是个能拉开差距的典型场景。

当时团队有点忙,我临时把这个需求分别交给了三个"人":

  • 小王,工作1年半的初级开发
  • 老陈,工作6年的高级开发
  • Cursor(我给它写了一个详细的Prompt)

三份代码我都仔细看过了。

看完之后,我沉默了很久。


第一个:小王(工作1年半)

我把需求文档发给他,他没有追问,当天下午就说:"做完了,测试通过了。"

速度确实快。打开代码一看:

java 复制代码
@PostMapping("/refund")
@Transactional
public Result<Boolean> refund(@RequestBody RefundRequest request) {
    Order order = orderMapper.selectById(request.getOrderId());
    if (order == null) {
        throw new BusinessException("订单不存在");
    }
    if (order.getStatus() != OrderStatus.PAID) {
        throw new BusinessException("订单状态不支持退款");
    }
    // 退款金额写回
    order.setStatus(OrderStatus.REFUNDED);
    order.setRefundAmount(request.getRefundAmount());
    orderMapper.updateById(order);
    // 调用支付退款接口
    payService.refund(order.getPaymentNo(), request.getRefundAmount());
    // 库存回滚
    inventoryService.rollback(order.getProductId(), order.getQuantity());
    return Result.success(true);
}

功能逻辑是对的,基本流程都有,单元测试也过了。

但我看了两分钟,发现了几个问题:

问题1:没有幂等控制。 如果这个接口被重复调用两次(网络超时重试是很常见的),订单会被退款两次,库存回滚两次。这是生产事故级别的bug。

问题2:退款金额没有校验上限。 request.getRefundAmount() 没有和订单实际支付金额做比对,理论上可以传一个比实际支付金额更大的数字。

问题3:payService.refund 失败后没有补偿机制。 调用第三方支付退款失败了怎么办?状态已经改了,但钱没退出去,这个烂摊子谁来收拾?

我去找小王聊。

他说:"我以为测试通过了就行。"

这就是问题所在。他交付的是一个"能跑的功能",不是一个"可以上生产的方案"。

他想到了正常流程,但没有想过任何一个异常流程。


第二个:老陈(工作6年)

老陈拿到需求之后,没有立刻动手。

他先发了一条消息给我,问了3个问题:

  1. 退款是全额退款还是支持部分退款?
  2. 退款金额打回原路还是可以退到其他账户?
  3. 退款后库存需要实时回滚,还是等退款成功回调之后再回滚?

我当时看到这3个问题,愣了一下。

这3个问题,需求文档里都没写清楚。

我去问了产品,产品想了半天,说:"支持部分退款,退回原路,库存等退款成功回调之后再回滚。"

这3个答案,直接影响了整个接口的设计。如果不提前搞清楚,后面改起来成本极高。

老陈花了半天设计,画了一个退款状态机:

复制代码
PAID → REFUNDING → REFUNDED(退款成功)
                 → REFUND_FAILED(退款失败)

然后核心实现加了分布式锁防并发,加了幂等Key防重复提交,支付回调之后再触发库存回滚:

java 复制代码
@PostMapping("/refund")
@Transactional
public Result<Boolean> refund(@RequestBody RefundRequest request) {
    // 幂等校验
    String idempotentKey = "refund:" + request.getOrderId() + ":" + request.getRefundNo();
    if (!redisLock.tryLock(idempotentKey, 10, TimeUnit.SECONDS)) {
        throw new BusinessException("请勿重复提交退款申请");
    }
    try {
        Order order = orderMapper.selectById(request.getOrderId());
        // 金额校验:退款金额不能超过实际支付金额
        if (request.getRefundAmount().compareTo(order.getPayAmount()) > 0) {
            throw new BusinessException("退款金额不能超过支付金额");
        }
        // 更新状态为退款中
        order.setStatus(OrderStatus.REFUNDING);
        orderMapper.updateById(order);
        // 调用支付退款,异步等待回调
        payService.refund(order.getPaymentNo(), request.getRefundAmount(), request.getRefundNo());
        return Result.success(true);
    } finally {
        redisLock.unlock(idempotentKey);
    }
}

代码质量明显比小王高了一个档次。

但我也发现了一个问题:他额外设计了一套"退款规则引擎",支持按商品类型配置不同的退款策略。

我问他:"这个规则引擎现在用得上吗?"

他说:"现在用不上,但以后可能会扩展。"

我沉默了一下。

这个功能,我们至少6个月内不会用到。提前设计意味着提前写代码、提前测试、提前维护。这不是严谨,这是过度设计。

他交付的是一个高质量的方案,但在某些地方,超出了当前的实际需要。


第三个:Cursor(AI)

我给Cursor写了一个比较详细的Prompt:

复制代码
实现一个订单退款接口,要求:
1. 支持部分退款,退款金额不能超过支付金额
2. 加分布式锁防并发,加幂等Key防重复提交
3. 退款成功后的库存回滚由支付回调触发,本接口只负责发起退款
4. 退款状态:REFUNDING → REFUNDED / REFUND_FAILED
5. 技术栈:Spring Boot 3, MyBatis-Plus, Redis
6. 异常用BusinessException,返回值用Result<T>

5分钟后,Cursor生成了一份代码,大约200行。

代码结构清晰,异常处理很全面,甚至考虑了我没有提到的一些边界情况,比如订单不存在、订单已经在退款中等等。

但我发现了一个问题。

它生成的幂等Key是这样的:

java 复制代码
String idempotentKey = "refund:" + request.getOrderId();

只用了订单ID。

这意味着,同一个订单如果第一次退款50元失败了,第二次想重新发起退款请求,会被直接拦截------因为幂等Key一样。

正确的做法是用"订单ID + 退款单号"作为幂等Key,每次退款请求都有独立的退款单号,互不影响。

这不是一个语法错误,测试也不会暴露它。这是一个业务逻辑错误,只有理解了退款业务流程的人,才能发现它。

除此之外,AI还有一个地方明显不足:它不知道我们公司有一条内部规定------VIP用户的退款走单独的优先通道,需要先判断用户等级

这条规则在任何文档里都没有,只存在于老员工的脑子里。

AI不知道,所以它没有处理。

它交付的是一段逻辑正确、结构清晰的代码,但不是一个理解了我们业务的方案。


我为什么沉默了

看完三份代码,我坐在那里想了很久。

我沉默,不是因为AI赢了。

也不是因为高级程序员赢了。

我沉默,是因为我意识到一件事:

小王能做的事,AI已经做得更快、更全面了。

小王花了半天写的代码,Cursor用了5分钟,而且覆盖了更多边界情况。如果小王继续只是"接需求、写代码、测试通过就交差",他的竞争对手已经不是其他初级程序员了,而是每个人手里的AI工具。

但老陈的价值,也不在于他写的那200行代码。

他的价值,在于那3个追问

这3个问题,AI问不出来,因为AI不知道哪些地方需要追问。这3个问题,小王也没想到,因为他的经验还不够。

只有老陈,在拿到需求的第一时间,就知道这里有3个坑,需要先搞清楚再动手。

这才是高级程序员真正值钱的地方。

不是他写代码的速度,不是他记住了多少API,而是他理解业务的深度 ,以及由此产生的判断力------知道哪里有坑,知道哪里要追问,知道哪里可以简化,知道哪里不能省。

这个判断力,是AI替代不了的。


3点真实的建议

做完这个对比,我想说3件具体的事。

第一,如果你是初级程序员,现在最重要的一件事是:养成追问需求的习惯。

拿到需求,先别动手写代码。先问自己:这里有没有没写清楚的地方?有没有异常情况没有覆盖?有没有将来可能变化的部分?

这个习惯,是从初级到高级最关键的跨越。代码写得快不快,不是差距所在。

第二,用AI提升执行效率,但把省出来的时间投入到理解业务上,而不是摸鱼。

AI帮你把写代码的时间从半天压缩到1小时,这1小时不是用来早点下班的,是用来去跟产品聊、去理解这个功能背后的业务逻辑、去想那些代码之外的问题。

第三,学会review AI的代码,重点找那20%它不懂的地方。

AI的代码,功能逻辑通常是对的,结构通常是清晰的。但它不知道你们公司的内部规定,不知道你们业务的特殊场景,不知道这个幂等Key的设计是否符合你们的退款流程。

这20%,就是你的价值所在。


最后说一句让我印象最深的话。

事后我问老陈,你怎么看AI写的代码?

他看了一眼,说:

"代码写得不错。但它不知道我们昨天刚开完会,决定把VIP退款改成异步处理。"

我笑了。

AI让写代码变容易了,但让成为一个好程序员变得更难了。

因为你再也没有借口说"我没时间思考"了。


你们团队有没有类似的经历?欢迎评论区聊聊。


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

相关推荐
sTone873754 小时前
web后端开发概念: VO 和 PO
java·后端·架构
SimonKing5 小时前
JetBrains+Qoder变身Agentic 编码平台,媲美Cursor、Trae等AI编程平台
java·后端·程序员
Seven975 小时前
NIO:解开非阻塞I/O高并发编程的秘密
java
华仔啊17 小时前
千万别给数据库字段加默认值 null!真的会出问题
java·数据库·后端
老赵全栈实战20 小时前
【每日一技MyBatis trim标签核心用法
java·mybatis·orm
beata20 小时前
Java基础-19:Java 死锁深度解析:从原理、检测到预防与实战指南
java·前端
吾日三省Java1 天前
Spring Cloud架构下的日志追踪:传统MDC vs 王炸SkyWalking
java·后端·架构
爱玩泥巴的小t1 天前
new Thread().start()底层做了什么?
java
码路飞1 天前
GPT-5.4 Computer Use 实战:3 步让 AI 操控浏览器帮你干活 🖥️
java·javascript