上周三下午,我 review 了一个 PR。
三百多行,React 组件加一堆工具函数,来自我们组新来的一个同学。代码是 Cursor 写的,他自己改了几处,测试过了,UI 跑起来没问题。
我看了二十分钟,合了。
晚上回家路上我突然反应过来一件事:那三百行里,我其实没完全看懂大概有六七十行在干嘛。 不是代码写得烂,变量名规范、类型完整、注释也有。但有几段逻辑,我知道它"能跑",但我说不清它"为什么这么写"。
这个感觉很不舒服。以前 review 别人的代码,看不懂就让人过来讲两句,或者自己倒杯水回来再读一遍。但这次不一样------代码是对的,测试是过的,我卡住的地方在于:我找不到一个具体的理由要求他改。
一、以前说"代码写得慢",现在说"你倒是看看啊"
我入行那会儿,团队里最怕的是那种写代码飞快但从来不写测试的人。代码提交一堆,跑起来三天两头出问题,review 的时候你能抓出一把"这里没判空""这个边界没处理"。
那时候 review 是有明确靶子的。逻辑漏洞、命名混乱、缺错误处理,你看一眼就能说"这里不行,回去改"。
现在靶子变模糊了。
AI 生成的代码,下限被抬得很高。判空有、边界有、错误处理有,命名还挺规范。你打开 diff,第一眼感觉是"嗯,写得比我还整齐"。
但你还是觉得哪里不对。然后你往下翻,发现某段逻辑用了三层嵌套的 useEffect 去处理一个其实用 useMemo 就能算出来的东西。或者一个组件里塞了三种不同的数据获取方式------一个 fetch、一个 useSWR、一个从 props 传下来的。
不是错,是"没必要"。
而这种"没必要"是最难 review 的。你很难指着一个能跑、测试能过、没安全问题的代码说:"兄弟,这个抽象有点多余。"因为对方大概率会回你一句:"那不然怎么写?"
你一时半会儿还真答不上来。
二、我最近干得最多的事,是"往回拆"
上个月我们做一个内部的数据看板。我自己用 Claude Code 起了个头,跟它说"帮我搭一个带筛选和分页的表格页"。
十分钟,页面出来了。筛选器、表格、分页、loading 状态、空状态,一应俱全。我跑了一下,挺好。然后又让它加一个"导出 Excel"的按钮。
又两分钟,加完了。
然后我让它"把筛选条件同步到 URL 上,刷新页面能恢复"。
它做到了。用的是 useSearchParams 加一个 useEffect 监听,逻辑写得挺完整。
但当我打开那个文件的时候,它已经四百多行了。一个表格页,四百多行。里面有三个 useEffect、两个 useState 管着同一份数据的两个副本、一个 useRef 存着"上一次的筛选值"、还有一个 useCallback 包着一个其实只被调用一次的函数。
我坐在那儿看了五分钟,然后开始往回拆。
把两个 useState 合成一个,删掉那个 useRef,把 useCallback 去掉,把其中一个 useEffect 里的逻辑挪到事件处理函数里。
拆完之后两百出头。
功能一行没少,测试照样过,但我花了四十分钟。
这四十分钟不是因为 AI 写得烂。是因为 AI 写的时候没人拦着它。你每说一句"再加个功能",它就在文件里多堆一层。它不知道"够了"在哪里,它只知道"你要的我都给你了"。
三、我现在 review 的时候会问一个很蠢的问题
"这段代码,如果明天产品说要改需求,你打算从哪一行开始动?"
这个问题很土,也不严谨。但我发现它特别好用。
AI 写的代码有一个很隐蔽的问题:它经常把"改起来最方便"的地方,放在"读起来最绕"的地方。
比如它会把一个状态的计算逻辑,拆到三个不同的 useEffect 里,每个 useEffect 只管一小段。跑起来是对的,因为 React 会按顺序执行。但你明天要改这个计算规则,你得同时打开三个地方,还得在脑子里跑一遍它们的执行顺序。
你问 AI"为什么拆成三个",它会给你一个听起来很有道理的解释:"关注点分离"。
但你心里清楚,真正的关注点只有一个:这段逻辑明天会不会被人改。
我现在的做法是,只要 review 到"三个以上 useEffect 联动"的地方,就要求合并。不是因为它错,是因为我付不起下次改它的时间。
四、有件事我到现在也没想明白
团队里有个同事,用 AI 用得比我猛。他基本不手写组件了,全靠 Agent。但他的代码 review 起来特别舒服。
我观察了一阵,发现他有一个习惯:每次让 AI 生成完之后,他会自己重写一遍。
不是全改,是把 AI 写的结构打散,按他自己的习惯重新组织。变量名换成他习惯的缩写,函数拆成他习惯的粒度,注释删掉一半。
我问他:"你这不相当于白让 AI 写了吗?"
他说了一句话,我记到现在:
"AI 帮我写的是我不知道怎么写的部分。我知道怎么写的部分,我不让它碰。"
这句话听起来像鸡汤。但我后来试了试,确实不一样。
以前我是"让 AI 把整个组件写完,我再改"。现在我是"先自己写骨架,把数据流和状态边界定好,再让 AI 填里面的细节"。
后者慢一点,但 review 起来快很多。因为骨架是我定的,我看得懂。
至于前者为什么让我难受------我到现在也没完全想明白。可能是"看不懂自己的代码"这件事本身让人不安,哪怕它是对的。
五、说点实在的
如果你也在带人,或者也在 review AI 参与的代码,我有三个不太成熟的经验:
第一,别在 diff 里直接 review。 把文件下载下来,在本地打开,看整个文件长什么样。AI 写的代码在 diff 里看着很整齐,但整个文件读下来经常是"每段都对,合起来很怪"。
第二,看到"三个以上 useEffect 互相依赖",就要求合并。 这不是代码规范问题,是维护成本问题。AI 很喜欢用多个 useEffect 来"分步处理",但它不承担下次改的时候要同时在三个地方改的代价。
第三,问那个很蠢的问题:"明天改需求,从哪一行动?" 如果对方(或者你自己)答不上来,说明这个结构有问题,不管它跑得多对。
最后说一句可能不太讨喜的话。
AI 把"写出能跑的代码"这件事的成本压得很低。低到我有时候会觉得,review 比写还累。
但累归累,该看还得看。因为上线之后出问题,用户骂的不是 Cursor,是你。