领导:有AI还要看懂代码干嘛?我直接沉默
领导:这个AI工作流页面怎么写这么久?
我:拆12个阶段,每个阶段AI要反复生成调试,几十轮代码我每一行都手动核对,开了3个Agent并行都提速有限。
领导:代码你看过转头就忘,反正有AI,你没必要懂代码啊?
我:……当场沉默。
提问:大家用AI写代码,每段都要手动Review吗?
我认为是要的!但是分复制和简单功能,复制功能需要知道数据从哪来、怎么变、到哪去
核心心态:不要读 AI 代码,要怀疑 AI 代码。
AI 写的代码在试图说服你它是对的,但你不该信,你要自己证明它是对的。
一、AI 代码和人写代码的本质区别
人写的 bug 通常一眼能看出来——拼错变量名、逻辑写反、漏了await。
AI 写的 bug 是你读三遍都觉得没问题,上线之后才炸。它不报错,它静默地给你一个错误结果。
所以 review AI 代码不能用"通读一遍找问题"的方式,要用针对性的策略。
二、六条实战经验
1. "看起来对"是最大的陷阱——盯数据流转
AI 代码最大的问题不是写错,是写得像对的。
典型例子:
constid=Number(element.getAttribute("data-asset-id"));看着完全没问题。但如果 DOM 上属性被意外删了,getAttribute返回null,Number(null)结果是0——不是NaN,是0。这个id = 0会悄悄往下走,可能匹配到另一个素材,产生极难排查的数据错乱。
怎么审:
不要通读代码。重点盯数据从哪来、怎么变、到哪去。每个外部输入(DOM 属性、接口返回、用户输入)进来的地方,都问一句:这个值如果不是我预期的怎么办?
关注点:
- 类型转换:
Number()、parseInt()、JSON.parse()的输入如果是null/undefined/非法字符串会怎样? - 可选链终点:
a?.b?.c最终是undefined时,下游代码能处理吗? - 数组越界:
arr[0]前有没有判空?find()返回undefined后有没有处理?
2. 别坐着看代码——像不耐烦的用户一样操作
AI 写代码时,脑子里的用户是一个乖乖按流程操作的理想人。但真实用户会:
- 疯狂连续点击
- 复制粘贴一坨带格式的富文本
- 打了一半中文突然按删除
- 页面还没加载完就开始操作
- 在 iOS Safari 上用(很多 DOM API 行为完全不同)
- 网络断了还在点提交
怎么审:
打开页面,像一个不耐烦的用户那样操作。快速点击、中途切换、粘贴乱七八糟的内容、用手机试。
90% 的 AI 代码 bug 都是这样发现的,不是看出来的。
重点场景:
- 连续快速触发同一操作(防抖/节流有没有?)
- 异步操作中途切换页面(取消机制有没有?)
- 输入法组合态下的各种操作(中文、日文输入法)
- 粘贴非纯文本内容
- 弱网 / 断网环境
3. AI 爱用过时 API,而且用得特别自信
AI 的训练数据里有大量过时代码。它不知道"现在不该用了",只知道"以前很多人这么用"。而且它用废弃 API 时非常自然,注释还写得头头是道。
常见的过时 API:
| 废弃 API | 应该用 |
|---|---|
document.execCommand() | Clipboard API / InputEvent |
KeyboardEvent.keyCode | KeyboardEvent.key |
Event.returnValue | Event.preventDefault() |
XMLHttpRequest直接用 | fetch或项目的 axios 封装 |
componentWillMount(React) | useEffect |
$on/$off/$once(Vue 2 事件总线) | mitt / provide-inject |
怎么审:
遇到你没见过的 API、或者"总觉得有更好的写法"的地方,花 30 秒去 MDN 搜一下。看有没有 Deprecated 标记。
4. AI 的注释是在"表演懂了"
这是最容易分辨 AI 代码的特征。AI 喜欢给每个函数写一段"正确的废话"。
典型反面:
/** 获取节点在父节点中的位置,用于删除 token 后把光标放回原来的元素节点。 */functiongetNodeIndex(node:Node){if(!node.parentNode)return0;returnArray.prototype.indexOf.call(node.parentNode.childNodes,node)asnumber;}前半句"获取节点在父节点中的位置"——函数名已经说了。后半句是调用场景,不是函数本身需要说明的东西。
真正有价值的注释应该回答"为什么":
- 为什么用
Array.prototype.indexOf.call而不是转数组? - 为什么
parentNode为空时返回 0 而不是 -1? - 为什么这里不能用某个更简单的替代方案?
怎么审:
直接问自己:把注释全删了,我能看懂代码吗?
- 能看懂 → 注释多余,删掉或精简
- 看不懂 → 注释应该解释你看不懂的那个部分,而不是你已经看懂的部分
5. AI 不会质疑你的方向——但你自己要质疑
你让 AI 写一个 contentEditable 编辑器,它就老老实实给你写。它不会跳出来说:
“contentEditable 是出了名的坑多,跨浏览器行为不一致。你考虑过 Tiptap / Prosemirror 吗?”
AI 是执行者,不是顾问。你说什么它做什么。
怎么审:
review 之前先退一步想:这个问题该用这种方式解决吗?
特别是当 AI 写了一大坨复杂代码的时候——越复杂,越要怀疑是不是方向就错了。可能一个成熟的第三方库 50 行就搞定了。
警惕信号:
- 一个 composable 超过 300 行
- 手动操作 DOM 超过 20 处
- 自己实现了一套状态管理 / 事件系统 / 路由逻辑
- 处理了大量浏览器兼容细节
6. 最高效的审法:试着删
AI 代码 review 最高效的方法就是试着删东西:
| 试着删 | 如果没影响说明 |
|---|---|
| 一个函数 | 没人调用,是死代码 |
| 一个参数 | 是多余的,简化掉 |
| 一段错误处理 | 防御的场景根本不会发生 |
| 一个拆出去的小函数 | 内联回去更清楚,不该拆 |
| 一段注释 | 代码本身已经够清楚了 |
AI 生成的代码通常有20-30% 可以精简掉而不影响功能。精简后代码更好维护。
三、Review 流程(实操顺序)
不要从第一行开始往下读。按这个顺序来:
第一步:先跑起来(5 分钟)
打开页面,走一遍正常流程,再故意搞几次异常操作。看控制台有没有报错。
这一步能发现 60% 的问题。
第二步:盯入口和出口(10 分钟)
只看:
- 函数的参数从哪来(用户输入?DOM?接口?)
- 返回值/副作用到哪去(存到 store?发到后端?改了 DOM?)
- 类型转换和边界处理
第三步:查可疑 API(5 分钟)
搜代码里的:
innerHTML、v-html→ XSS 风险document.execCommand→ 废弃 APIeval、new Function→ 安全风险any、as any→ 类型逃逸console.log→ 该删没删的调试代码
第四步:对照项目规范(5 分钟)
- 文件放对目录了吗?
- 命名风格和周围代码一致吗?
- 状态管理用的是项目约定的方式吗?
- import 路径用了
@/别名吗?
第五步:精简(10 分钟)
试着删代码。删不动的就是核心逻辑,删得动的就是冗余。
四、一句话总结
先跑再看,盯数据流,查过时 API,怀疑方向,最后做减法。
不要被 AI 代码的工整结构和流畅注释迷惑。代码好不好,不看写得多整齐,看的是上线之后会不会炸。
