初级、高级程序员和AI处理同一需求,结果差异大,谁的表现最让人意外?

摘要:上个月,我们有个新功能要做:实现一个订单退款接口。 需求不复杂,但涉及金额变更、库存回滚、状态流转,刚好是个能拉开差距的典型场景。 当时团队有点忙,我临时把这个需求分别交给了三个"人":
上个月,我们有个新功能要做:实现一个订单退款接口。 需求不复杂,但涉及金额变更、库存回滚、状态流转,刚好是个能拉开差距的典型场景。 当时团队有点忙,我临时把这个需求分别交给了三个"人": 小王,工作1年半的初级开发 老陈,工作6年的高级开发 Cursor(我给它写了一个详细的Prompt) 三份代码我都仔细看过了。 看完之后,我沉默了很久。 第一个:小王(工作1年半) 我把需求文档发给他,他没有追问,当天下午就说:"做完了,测试通过了。" 速度确实快。打开代码一看: @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个问题: 退款是全额退款还是支持部分退款? 退款金额打回原路还是可以退到其他账户? 退款后库存需要实时回滚,还是等退款成功回调之后再回滚? 我当时看到这3个问题,愣了一下。 这3个问题,需求文档里都没写清楚。 我去问了产品,产品想了半天,说:"支持部分退款,退回原路,库存等退款成功回调之后再回滚。" 这3个答案,直接影响了整个接口的设计。如果不提前搞清楚,后面改起来成本极高。 老陈花了半天设计,画了一个退款状态机: PAID → REFUNDING → REFUNDED(退款成功) → REFUND_FAILED(退款失败) 然后核心实现加了分布式锁防并发,加了幂等Key防重复提交,支付回调之后再触发库存回滚: @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是这样的: 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实验室 不讲概念,只谈实战 代码开源,每周更新