上个月给一个后端服务加数据校验,需求不复杂:几个核心接口的入参做运行时校验,老调用方不能受影响。我把需求整理成一段结构化描述丢给编码助手,几分钟后,六个文件被改完,顺手还补了几个单测。类型检查通过,测试全绿,终端里一排对勾。
我当时挺得意的。第二天联调,问题全冒出来了:null 和 undefined 的处理跟后端约定对不上,几个边界值直接放行;新校验模块被卷进一个循环依赖,构建不报错,运行时偶发初始化异常;还有一个测试,断言的居然是错误的行为 ------ 等于把 bug 固化成了预期结果。
这事之后我改了工作方式。一句话总结:描述需求的质量决定起点,验收的质量决定终点。 生成得再快,最后能不能放心上线,看的是你怎么审。
第一眼:别急着看代码,先对需求
拿到 AI 的代码,很多人上来就欣赏实现写得好不好看。我的顺序反过来:先拿业务需求逐条对它做的事。AI 最大的坑不是语法错,是语义漂移------ 它对某个词的理解跟你不完全一样,但它写得很自信。
举个真实例子。需求是 "满 100 减 10,不足 100 不打折",AI 给的代码是 return price * 0.9。99 元不该打折,它打了;200 元该减 10,它减了 20。代码能跑,语法漂亮,做的根本不是你要的事。
所以第一遍我拿着接口签名、方法参数、返回值,跟业务规则一条条核对,对不上直接打回重写,后面的时间全省了。
第二眼:先读 diff,再跑任何命令
测试是 AI 写的,代码也是 AI 改的,都不算原始证据,diff 才是。
bash
git diff --stat
先看改动范围;
css
git diff --check
顺手揪出尾随空格和冲突标记 ------AI 生成代码留这种尾巴的频率不低。
范围合理之后,我重点盯四类改动:
- 条件判断(语义漂移高发区)
- 新增的 import(可能带进循环依赖)
- 被删掉的代码(可能是别人踩坑之后加的防御逻辑)
- 测试文件(后面单独说)
改动密集的地方用 --word-diff 按词比,比按行看清楚得多。 有一次它 "顺手" 删了一段看起来冗余的重试逻辑,那段其实是半年前线上超时事故之后加的。从那以后,删除的代码我一行行确认。
第三眼:专攻边界和安全,AI 在这里装傻
AI 写正常流程行云流水,一到边界就开始糊弄。参数为空、数组越界、除零、超时、并发冲突、第三方接口抽风 ------ 这些它不主动替你想。null 那个 bug 就是典型:模型觉得 null 和 undefined 差不多,写了严格相等,null 直接放行,类型检查一声不吭。
安全上同理,它不是安全专家。SQL 字符串拼接、密钥硬编码、日志里打印 token、用户输入不做校验转义,这些问题功能层面挑不出毛病,出事都在上线之后。它还热衷于推荐你没见过的依赖,来源和版本都要查一查,别让一个不明来路的包混进生产环境。涉及钱、用户数据、权限的模块,这段我逐行看,不看快。
还有一类问题本地根本看不出来:循环里查数据库的 N+1、不分页的全表加载、锁粒度拍脑袋、线程池参数乱配。本地一百条数据丝般顺滑,上线数据量一涨,先把连接池打满。 所以每段代码我都问一句:放到线上量级,它会怎样?
第四步:测试这块,我不信 AI 的全绿
AI 写测试有个隐蔽毛病:先写了实现,再照着实现反推测试。它断言的是 "代码按它写的方式运行",离 "代码按需求要求的方式运行" 还差一层。这种测试全绿也没用,反而给你一种已经验证过的错觉。
我的做法是验收用例自己设计,独立于它的测试:正常值、边界值、空值、异常值各来一组,输入和预期输出列成表。再狠一点,做反向校验 ------ 故意篡改一个返回字段,看测试红不红。红不了的假用例,直接扔。单元测试补齐之后,集成测试照跑,模块之间的账要单独算。
第五步:丑话说在上线前
命名清不清楚、方法职责单不单一、注释够不够,这些决定三个月后团队里其他人接手时是顺路还是酷刑。 AI 起的名字有时很怪,processData、handleStuff 这种词,眼下能跑,半年后没人说得清它处理的是什么数据。结构上它还容易过度设计,明明一个函数能解决的事,给你套三层抽象。AI 能帮你写代码,维护终归是人来扛。
上线前还要确认:日志有没有、监控指标有没有、告警有没有、出了问题几分钟能回滚、回滚之后数据能不能对上。这些它不替你设计,你不提前想,出事就是凌晨三点爬起来手忙脚乱。
最后,记一本账
验收里踩过的坑,我随手记在一个文档里,每次写需求描述之前扫一眼。 null 那次之后,我的描述里多了一句 "注意区分 null 和 undefined";循环依赖那次之后,多了一句 "新增 import 前确认依赖方向"。半年下来,同样的问题在验收阶段出现的次数肉眼可见地变少 ------prompt 和验收是配合着长的,前者少犯错,后者兜住剩下的。
AI 是个能力很强、但不负责的同事。代码交付那一刻,它的工作就结束了,接下来的每一行,签字的人是你。 那晚我把 null 的 bug 修完,顺手在文档里添了第 27 条。下一条会是什么,我还不知道。