代码评审那一轮:在别人的代码里找 bug

2026-08-21 · 9 分钟阅读

代码能编译。如果有测试,测试也通过。而在这段代码里,埋着两三个深浅不一的问题——你挖到多深,就是这一轮的分数。

为什么公司要考这一轮

读代码占了这份工作的大部分。工程师花在理解已有代码上的时间,远多于写新代码,而空白编辑器永远考不出这一点,这一轮可以直接考。

它还很省:二十分钟、一段准备好的代码,面试官就能知道你会不会注意到竞态条件、能不能把真问题和风格偏好分开,以及你怎么提出批评——这一点很重要,因为下个月你就要评审同事的代码了。

按这个顺序看

  • 先看正确性。它对所有输入都做到了它声称的事吗,而不只是对例子?差一错误、空集合、null、零这个边界。
  • 再看失败路径。依赖挂掉时会怎样——网络超时、文件不存在、解析失败。吞掉的异常和空的 catch 块住在这里,而且是最常被埋的一种。
  • 然后是并发与资源。先检查后动作的模式、共享可变状态、打开了但在错误路径上没释放的连接。一个跳过了 close 的提前 return 是经典,正因为它看起来人畜无害。
  • 接着是性能,但只在要紧处。循环里的查询是真发现;五个元素的字符串拼接略低效,是噪音。
  • 风格放最后,而且要短。命名和格式值一句话,不值五句。一上来就说这些,等于告诉面试官你没找到真东西。

陷阱:停在第一个 bug

面试官通常会埋好几个深浅不同的问题。靠上的位置有一个显眼的——少了个空值判断,十秒就能看见——它存在的意义,是看你找到之后会做什么。

宣布完就停下的人,回答的是另一个问题。记下它继续往下读的人,会在四十行之后找到那个资源泄漏,而整轮就是围绕它设计的。

把浅的那个快速说掉,然后继续:“第四行少了空值判断,很好改。我先往下看完再提修改建议。”

怎么说,同样在打分

这一轮同时也在考你怎么给反馈,因为这段代码出自一个假想的同事,而面试官正在想象你对着一个真人说这些话。

两个习惯读起来很好。区分严重程度——明确说哪些发现会阻塞合并、哪些只是偏好,因为把所有事都当成同等紧急的评审者,合作起来非常累。以及描述故障,而不是描述作者:“两个请求同时到达时,这里会返回过期数据”,而不是“这里写错了”。

如果你更想问作者一句而不是断言一个 bug,就直接说出来:“我会先问这个方法有没有并发调用——如果有,这个计数器就不安全。”真实的评审意见就长这样。

最常被埋的几个 bug

  • 被吞掉的错误。catch 里什么都不记就继续,于是故障在下游变成隐形的,而不是在源头大声报出来。
  • 泄漏的资源。顶部打开、底部关闭,中间一个提前 return 直接跳过了关闭。
  • 先检查后动作的竞态。读一个值、据此判断、再写回去——单线程没问题,两个调用者同时到达的瞬间就错了。
  • 可变的默认值或共享的缓存键。本该每次调用独立的状态却跨调用留存,产生的 bug 只在有负载时才出现。

如果这段代码其实没问题

偶尔那段代码基本是对的,而这一轮考的是你会不会为了显得仔细而编造问题。编造,就是失败。

正确的回答是说出你检查了什么、结果是干净的,然后说出你在批准之前还想知道什么:“我能看到的这些情况下逻辑是成立的。我想知道上游调用失败时它怎么表现,另外我会补一个空输入的测试——但这里没有需要我阻塞的东西。”

这个回答展示的是一套评审流程。三个编造出来的小毛病展示的是相反的东西。

副驾驶在哪里帮得上

Interview Copilot 实时跟着这一轮,在对方还在说话时就把结构放到你屏幕上:这道题真正在问什么、哪个约束才要紧、哪个取舍值得说出口。不是一份照读的稿子,而是你用自己的话开口时可以扶着的架子。

FAQ

代码评审面试是什么?

面试官给你一段埋了问题的代码,问你会改什么。它考的是你能不能读懂陌生代码、分得清什么重要,以及能不能给出同事真能照着改的反馈。

评审代码时应该先看什么?

先看正确性,再看失败路径、并发与资源,然后才是性能,风格放最后且只值一句话。一上来就说命名和格式,等于告诉面试官你没找到真问题。

找到一个 bug 之后就可以停了吗?

不能。面试官通常埋了好几个深浅不同的问题,靠上的那个显眼的就是用来看你找到之后会做什么的。快速说掉它,然后继续往下读。

如果代码其实没问题怎么办?

不要编造。说出你检查了哪些方面、结果是干净的,再说出你在批准前还想知道什么——这展示的是一套评审流程,而编造三个小毛病展示的是相反的东西。

应用在这里如何帮忙

继续阅读