上个月我们有个新功能要做实现一个订单退款接口。需求不复杂但涉及金额变更、库存回滚、状态流转刚好是个能拉开差距的典型场景。当时团队有点忙我临时把这个需求分别交给了三个人小王工作1年半的初级开发老陈工作6年的高级开发Cursor我给它写了一个详细的Prompt三份代码我都仔细看过了。看完之后我沉默了很久。第一个小王工作1年半我把需求文档发给他他没有追问当天下午就说做完了测试通过了。速度确实快。打开代码一看PostMapping(/refund) Transactional public ResultBoolean 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()没有和订单实际支付金额做比对理论上可以传一个比实际支付金额更大的数字。问题3payService.refund失败后没有补偿机制。调用第三方支付退款失败了怎么办状态已经改了但钱没退出去这个烂摊子谁来收拾我去找小王聊。他说我以为测试通过了就行。这就是问题所在。他交付的是一个能跑的功能不是一个可以上生产的方案。他想到了正常流程但没有想过任何一个异常流程。第二个老陈工作6年老陈拿到需求之后没有立刻动手。他先发了一条消息给我问了3个问题退款是全额退款还是支持部分退款退款金额打回原路还是可以退到其他账户退款后库存需要实时回滚还是等退款成功回调之后再回滚我当时看到这3个问题愣了一下。这3个问题需求文档里都没写清楚。我去问了产品产品想了半天说支持部分退款退回原路库存等退款成功回调之后再回滚。这3个答案直接影响了整个接口的设计。如果不提前搞清楚后面改起来成本极高。老陈花了半天设计画了一个退款状态机PAID → REFUNDING → REFUNDED退款成功 → REFUND_FAILED退款失败然后核心实现加了分布式锁防并发加了幂等Key防重复提交支付回调之后再触发库存回滚PostMapping(/refund) Transactional public ResultBoolean 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个月内不会用到。提前设计意味着提前写代码、提前测试、提前维护。这不是严谨这是过度设计。他交付的是一个高质量的方案但在某些地方超出了当前的实际需要。第三个CursorAI我给Cursor写了一个比较详细的Prompt实现一个订单退款接口要求 1. 支持部分退款退款金额不能超过支付金额 2. 加分布式锁防并发加幂等Key防重复提交 3. 退款成功后的库存回滚由支付回调触发本接口只负责发起退款 4. 退款状态REFUNDING → REFUNDED / REFUND_FAILED 5. 技术栈Spring Boot 3, MyBatis-Plus, Redis 6. 异常用BusinessException返回值用ResultT5分钟后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实验室不讲概念只谈实战 代码开源每周更新