一条评审评论大约四十秒写完,通常夹在两件事之间,写的人清楚自己的语气。读的人刚在这份代码上花了三天,正想收尾,而且听不到你的声音,于是自己补上一种语气——不是你的,是他的。有研究显示,邮件读者猜中作者本意的比例几乎和抛硬币差不多。
文字最先丢掉的不是友善,是权重。当面说时你会自然区分「小问题,名字有点怪」和「这条真的重要」,表情和语气会告诉对方哪个是哪个。但在评审工具里,每条评论都是同样的灰框、同样的字体,
nit: rename to userIds 和「任务重试时这张卡会被扣两次钱」长得一模一样。作者只能猜哪些可以反驳,最安全的猜法就是全部照做。十四条「done」不是认同,是服从。当每条评论权重相同时,剩下的唯一权重就是数量,十四条会被读成对整个 PR 的判决。文字还抹掉了问句的形状:「你为什么这里用 map?」当面带着好奇说是提问,打出来就成了要求自证,而不带理由的「为什么」读起来像指控。
可以这样写:先在评审顶部写一句总述——「整体不错。一件真事——第 84 行的重试。其余都是小事,可选。」它最先被读到,也改变下面每条评论被阅读的方式。再在每条评论开头标出权重:「Blocking:」「Non-blocking:」「Nit, ignore if you like:」。已有现成约定 Conventional Comments,但你不需要那套规范,只需要让作者能回答那个默默问的问题:我必须改吗?
把理由放进问题里。不要写「为什么用 map?」,改成「我可能漏了什么——用 map 是因为那些查找吗?我大概会用数组。」这样对方是在纠正你的猜测,而不是为自己的选择辩护。第二次回复之后就停手,文字里的讨论会自己升级,每条回复更长、措辞更小心,而小心读起来像冷淡。到第三轮,讨论的已经不是 map,而是谁对。可以说「文字里越写越长,有十分钟聊聊吗?」通话后在讨论串里补一行写清结论。
标签解决不了数量。二十五条都以「nit:」开头的评论,读起来还是二十五条。如果评审大部分是 nit,解法是更少的评论:把小事合并成一条,或放掉一些。过度软化则会埋掉真正重要的东西:「也许可以看看这里是不是有可能重试两次?」真正的 bug 被包了太多缓冲,读起来像可选,然后就被合并了。初级评审资深的人不需要更多缓冲,需要标签加一句直白的话:「Blocking,我认为——任务重试时这会跑两次。如果我读错了请告诉我。」资深的一方则相反:你的提问无论是否有意都是指令,「有没有考虑过用 map?」出自 staff 工程师之口,你就会得到一个 map,只有明说「真的可选,两种我都可以」才行。
同一条评论,出自不同人之口就是不同的评论。负责人的一句「嗯」比新人的一整段都重,文字不会掩盖职级,反而会放大它。实际做法是:别在小讨论上耗尽自己,把争论留给真正重要的那条。今年还多了一个版本:PR 里越来越多的代码由助手写成,评审者更累,累的时候评论更短,而短评论读起来像冷淡。还出现了一条全新的最差评论:「这是 AI 写的吗?」不管是不是,作者听到的都是「你没想过这件事」。如果你就是这个意思,留下有用的版本:「我看不懂这里为什么这样处理空值——能带我过一遍吗?」
下一次留评审时,先写那句总述,再写其他任何东西:一句话说清有几件事真正重要、是哪一件。然后回头给每条评论打上标签。如果你留下的 nit 比自己愿意收到的还多,删掉几条。你没有改变对代码的看法,只是把文字拿走的那部分放了回去。