搜 索

从入门到放弃:如何在 Code Review 中假装自己看懂了

  • 8阅读
  • 2025年07月12日
  • 0评论
首页 / 编程 / 正文

前言:Code Review 的残酷现实

理想中的 Code Review 是这样的:

sequenceDiagram participant A as 作者 participant R as Reviewer participant C as 代码库 A->>R: 提交 PR,附上详细描述 R->>C: 认真阅读每一行代码 R->>R: 深度思考业务逻辑和技术方案 R->>A: 提出有建设性的修改意见 A->>R: 感谢 Reviewer 的认真审查 A->>C: 修改并提交 R->>C: 再次确认,Approve C->>C: 代码质量显著提升

现实中的 Code Review 是这样的:

sequenceDiagram participant A as 作者 participant R as Reviewer participant S as Slack participant M as 会议 A->>R: 提交 PR,@你一下 S->>R: 各种消息轰炸 M->>R: 连续三个会议 R->>R: 瞟了一眼 PR,diff 有 800 行 R->>R: 滚动了一下,看起来没问题? R->>A: LGTM,先合了吧 Note over A,R: 三天后 A->>R: 那个 PR 有个 bug 上线了 R->>R: 我当时没仔细看... R->>A: 啊,这个我当时注意到了但忘说了

本文就是为第二种场景服务的——当你实在没时间、没精力、没背景知识看懂一个 PR 的时候,如何在不暴露自己的前提下,给出一个看起来很专业的 Review


第一章:Reviewer 画像分类

在学习话术之前,先了解 Code Review 中各种 Reviewer 的生存形态:

quadrantChart x-axis "看得少" --> "看得多" y-axis "说得少" --> "说得多" quadrant-1 "完美Reviewer" quadrant-2 "话痨Reviewer" quadrant-3 "橡皮图章" quadrant-4 "沉默观察者" "摸鱼型": [0.15, 0.2] "事必躬亲型": [0.9, 0.9] "挑刺专业户": [0.3, 0.85] "潜水围观型": [0.8, 0.15] "装懂高手": [0.25, 0.6] "真正大佬": [0.95, 0.75]

我们今天重点培养的是装懂高手的能力——看得不多,但说得有分量。


第二章:进入 PR 前的准备工作

不打无准备之仗。打开 PR 之前,先做三件事:

2.1 读 PR 标题和描述(必做,耗时 30 秒)

这是你唯一需要认真读的部分。PR 描述里通常包含:

  • 做了什么:给你提供评论的弹药
  • 为什么这样做:给你提供质疑的切入点
  • 测试了什么:给你提供追问的方向

如果 PR 没有描述,恭喜你,你拥有了第一条评论的素材:

「能否补充一下这个 PR 的背景和改动原因?方便 Review」

这条评论专业、合理、无懈可击,而且能为你争取到额外的理解时间。

2.2 看 Diff 的数字(必做,耗时 10 秒)

graph TD OPEN[打开 PR] --> CHECK{看 Diff 统计} CHECK --> |改动小于 50 行| SMALL[小 PR 可以认真看 这是难得的机会] CHECK --> |改动 50-200 行| MEDIUM[中等 PR 重点看关键文件 其余走话术] CHECK --> |改动 200-500 行| LARGE[大 PR 重点看入口和出口 中间假装看了] CHECK --> |改动大于 500 行| HUGE[巨型 PR 先问为什么不拆 这是合理要求 也为你赢得时间] SMALL --> REAL[认真 Review] MEDIUM & LARGE --> SKILL[启动话术体系] HUGE --> SPLIT[要求拆分 PR 专业且负责任] style REAL fill:#51cf66 style SKILL fill:#ffd43b style SPLIT fill:#74c0fc

2.3 看改动了哪些文件(必做,耗时 20 秒)

文件名能告诉你这个 PR 的性质:

文件特征含义你的策略
只改了 *Test.java纯测试改动问覆盖率,稳赚不赔
改了 *Controller.java接口层改动问入参校验和响应码
改了 *Repository.java数据层改动问索引和 N+1 问题
改了 *Config.java配置改动问各环境是否同步
改了 pom.xml依赖升级问是否测试过兼容性
改了几十个文件重构或格式化问有没有功能性改动混进来

第三章:万能评论话术库

这是本文的核心章节。以下话术经过真实 Code Review 场景验证,覆盖率达到 95% 以上的场景。

3.1 开场白类——让人觉得你认真看了

话术 A:整体肯定型

「整体看下来思路很清晰,几个小点想确认一下。」

效果:暗示你看完了全部代码,同时为后续问题铺垫。

话术 B:背景确认型

「想先确认一下理解是否正确:这个改动主要是为了解决 XX 问题,对吗?」

效果:即使你没看懂,也显得你在思考业务逻辑。如果理解错了,作者会纠正你,你反而能借此真正理解 PR 的目的。

话术 C:点赞占位型

「这个设计思路不错,之前类似场景我们都没处理这么优雅。」

效果:作者立刻对你有好感,后续即使你提不出什么实质意见,这个 PR 大概率也能顺利 Approve。

3.2 专业质疑类——让人觉得你很懂

话术 D:边界条件万能问

「这里如果入参为 null 或者空集合,会怎么处理?」

适用场景:任何有参数的方法。成功率 100%,因为总会有某个地方没考虑边界。

话术 E:并发安全万能问

「这个方法在高并发场景下是线程安全的吗?」

适用场景:任何 Service 层代码。即使方法本身是无状态的,作者也得解释一番,你就赢了。

话术 F:性能担忧万能问

「数据量大的时候这里的性能怎么样,有没有考虑过分页或者缓存?」

适用场景:任何涉及数据库查询或集合遍历的代码。

话术 G:异常处理万能问

「这里如果下游接口超时或者返回异常,上层会怎么处理?」

适用场景:任何有外部调用的地方。支付系统尤其好用。

话术 H:测试覆盖万能问

「这块逻辑有对应的单元测试吗?特别是异常分支。」

适用场景:任何你看不懂的代码。不管有没有测试,这个问题都成立。

3.3 看起来读懂了类——最高段位话术

graph LR subgraph 初级话术 人人会说 L1A[这里可以加个注释] L1B[变量名可以更语义化] L1C[魔法数字建议提成常量] end subgraph 中级话术 显得有经验 L2A[这个方法是不是可以复用现有的工具类] L2B[异常信息建议更具体一些方便排查] L2C[日志级别这里用 warn 还是 error 更合适] end subgraph 高级话术 显得很资深 L3A[这里的设计和我们 XX 模块有点类似 要不要考虑抽象一层] L3B[这个改动会不会影响 XX 的现有行为] L3C[从可维护性角度这里以后扩展方便吗] end L1A & L1B & L1C --> MID[中等水平印象] L2A & L2B & L2C --> GOOD[良好水平印象] L3A & L3B & L3C --> GREAT[资深水平印象]

高级话术的关键是关联到系统全局,显示你不只是在看这一个 PR,而是在思考整个系统。

3.4 Nit 评论类——小改动显示认真

「Nit」是 Code Review 中的高频词,意思是「小挑剔,可改可不改」,英文全称 Nitpick。妙处在于:

  • 提了意见,显得认真
  • 说了是 Nit,对方可以不改
  • 两边都不得罪
  • 实际上你什么都没看懂
Nit: 这里的变量名 `data` 可以改成 `accountList` 更语义化,不改也行。

Nit: 这个方法有点长了,以后有机会可以考虑拆一下,不影响这次合并。

Nit: 注释里有个错别字,`帐户` 建议改成 `账户`。(错别字类 Nit 是最安全的,跟代码逻辑完全无关)

第四章:各种棘手场景的应对策略

4.1 场景一:代码涉及你完全不懂的领域

比如密码学、复杂算法、你从来没接触过的业务模块:

graph TD UNKNOWN[遇到完全不懂的代码] --> STRATEGY{选择策略} STRATEGY --> S1[策略一:请教式提问] STRATEGY --> S2[策略二:转移焦点] STRATEGY --> S3[策略三:找盟友] S1 --> T1[这里的实现原理能简单解释一下吗 想更好地理解这个设计] S2 --> T2[这块逻辑本身没问题 我主要关注一下周边的错误处理] S3 --> T3[这块建议也拉上 XX 看一下 他对这个模块更熟悉] T1 --> RESULT1[作者给你科普 你顺便真的看懂了] T2 --> RESULT2[成功把注意力引开 没人发现你没看那块] T3 --> RESULT3[甩锅成功 而且显得你很负责任] style RESULT1 fill:#51cf66 style RESULT2 fill:#ffd43b style RESULT3 fill:#74c0fc

4.2 场景二:PR 改动了 800 行,你只有 5 分钟

这是最常见的困境。解决方案:战略性精读

第 1 分钟:读 PR 描述,搞清楚「改了什么」
第 2 分钟:看文件列表,找最核心的那 1-2 个文件
第 3 分钟:只看核心文件的入口方法和主逻辑
第 4 分钟:翻一下测试文件,看测试了什么场景
第 5 分钟:写评论

5 分钟后你能给出的评论:

「核心逻辑看起来没问题,主要改动集中在 TransferServiceprocess 方法,逻辑比之前清晰多了。

几个小点:

  1. processInternal 方法的异常有没有统一处理?
  2. 测试里好像没有覆盖金额为零的边界场景?

其他改动主要是重构,LGTM。」

对方看到这条评论会觉得:这哥们认真看过核心逻辑,而且提了有价值的问题。

4.3 场景三:你 Approve 了,结果出 bug 了

这是最需要话术的场景:

graph LR BUG[线上出 Bug 了] --> CAUSE{Bug 来源} CAUSE --> |和你 Review 的 PR 有关| PRESSURE[被问到你当时看没看] CAUSE --> |和你 Review 的 PR 无关| SAFE[松了一口气] PRESSURE --> RESPONSE{你的回应} RESPONSE --> R1[坦诚型 我当时没注意到这个分支 下次会更仔细] RESPONSE --> R2[技术型 这个 Bug 属于边界场景 静态分析很难发现 需要更完善的集成测试] RESPONSE --> R3[流程型 这说明我们需要 更严格的测试环境验证 而不只是依赖 Code Review] R1 --> HONEST[显得诚实有担当] R2 --> DEFLECT[把问题转移到测试覆盖] R3 --> PROCESS[把问题转移到流程建设] style HONEST fill:#51cf66 style DEFLECT fill:#ffd43b style PROCESS fill:#74c0fc
人生建议:R1 是最好的选择。承认自己没看到,然后说下次会怎么做。这比任何防御性话术都更赢得信任,而且不会让人觉得你在甩锅。

4.4 场景四:作者追问你某个技术细节

作者:你觉得这里用 CompletableFuture 还是用 reactive stream 更合适?
你(内心):我不知道这两个有什么区别。
你(嘴上):?

正确应对:

方案 A(最推荐):「这个要看你们的具体场景,如果整体技术栈已经是响应式的,统一用 reactive 更好;如果只是这一处异步,CompletableFuture 更轻量。你们当前栈是什么?」

把问题还给对方,显得你在做权衡,而不是不知道答案。

方案 B:「我觉得都行,你对这个更熟,你定吧,我更关注接口的行为是否正确。」

优雅放弃技术判断,把自己定位成业务正确性的把关人。


第五章:不同类型 PR 的专属话术

5.1 Bug Fix PR

✅ 专业开场:
「能否在描述里补充一下这个 Bug 的复现步骤?方便以后排查类似问题。」

✅ 核心追问:
「这个 Fix 有没有对应的回归测试?防止以后又被改回去。」

✅ 延伸关联:
「同样的逻辑在 XX 地方也有类似代码,要不要一起看看?」

5.2 新功能 PR

✅ 专业开场:
「这个功能的设计文档或者技术方案有吗?想对齐一下实现和设计的一致性。」

✅ 核心追问:
「异常情况下用户看到的是什么?前端有没有对应的错误处理?」

✅ 延伸关联:
「这个功能上线后怎么验证效果?有没有埋点或者监控指标?」

5.3 重构 PR

✅ 专业开场:
「重构前后行为完全一致吗?有没有哪些边界 case 在重构过程中可能被改变了?」

✅ 核心追问:
「测试覆盖率有没有变化?重构后的测试和重构前相比是增加了还是减少了?」

✅ 最安全的评论:
「这个重构让代码清晰多了,特别是 XX 部分。」
(XX 部分填你唯一看懂的那个方法名)

5.4 依赖升级 PR

✅ 没有任何背景知识也能问的问题:
「这个版本的 Release Notes 有没有 Breaking Changes?」
「CI 上所有测试都过了吗?」
「各个环境都验证过了吗?还是只在开发环境测了?」
「有没有影响到其他依赖这个包的模块?」

依赖升级 PR 是最适合「装懂」的场景,因为所有问题都是合理的,没人能说你没在认真看。


第六章:Code Review 的段位体系

graph TD D0[青铜:不看直接 Approve 俗称橡皮图章] D0 --> D1[白银:看了但不知道说什么 只会写 LGTM] D1 --> D2[黄金:能找出格式和命名问题 靠 Sonar 和 Lint 工具辅助] D2 --> D3[铂金:能发现逻辑漏洞和边界问题 每次 Review 都有实质意见] D3 --> D4[钻石:能从架构层面评审 发现设计问题而非实现问题] D4 --> D5[星耀:Read Between The Lines 看出作者想掩盖的技术债] D5 --> D6[王者:不需要看代码 光看 PR 描述就知道哪里有风险] style D0 fill:#868e96 style D1 fill:#c0c0c0 style D2 fill:#ffd43b style D3 fill:#74c0fc style D4 fill:#9775fa style D5 fill:#ff6b6b style D6 fill:#51cf66

本文教的是从青铜升到黄金/铂金的过渡期生存技能。

真正的目标是王者,但那需要的不是话术,而是时间和经验的积累。话术只是过渡期的拐杖,不是终点。

第七章:你不该假装看懂的情况

前面说了这么多「如何装」,最后必须说清楚什么时候不能装

graph TD REVIEW[开始 Review] --> RISK{评估风险} RISK --> |涉及核心支付逻辑| STOP1[不能装 必须认真看或者找懂的人一起看] RISK --> |涉及安全相关代码| STOP2[不能装 一个漏洞可能导致资损] RISK --> |数据库 Schema 变更| STOP3[不能装 改错了数据回不来] RISK --> |权限和鉴权相关| STOP4[不能装 出了问题是安全事故] RISK --> |一般业务逻辑| OK1[可以适当使用话术] RISK --> |格式和重构改动| OK2[话术完全适用] RISK --> |文档和注释更新| OK3[随便看看就行] STOP1 & STOP2 & STOP3 & STOP4 --> ACTION[要么认真看 要么明确说不够熟悉 请更合适的人 Review] OK1 & OK2 & OK3 --> SKILL[合理使用话术体系] style STOP1 fill:#ff6b6b style STOP2 fill:#ff6b6b style STOP3 fill:#ff6b6b style STOP4 fill:#ff6b6b style ACTION fill:#ffd43b style SKILL fill:#51cf66

这不是在开玩笑。支付系统的一个漏洞,轻则线上故障,重则资金损失。在核心路径上假装看懂了,后果是实实在在要承担的。


第八章:如何成为一个真正好的 Reviewer

既然写了这么多「装懂」的技巧,也应该说说真正好的 Code Review 长什么样:

graph LR GOOD[真正有价值的 Code Review] GOOD --> G1[提问而不是命令 考虑用 X 方法可能更好 vs 必须改成 X] GOOD --> G2[区分阻塞和建议 明确标注 Blocker 和 Nit] GOOD --> G3[给出理由 为什么要改而不只是改什么] GOOD --> G4[认可好的代码 不只是挑问题] GOOD --> G5[关注意图而非风格 别在格式上浪费时间 交给 Linter] GOOD --> G6[同步理解 不确定就先问再评论]

最好的 Reviewer 不是那个每次能找出最多问题的人,而是那个让作者在 Review 过程中成长的人。


结语:装懂是手段,看懂才是目的

graph LR START[刚加入团队 什么都不懂] --> FAKE[靠话术撑过最初几个月] FAKE --> LEARN[在话术的掩护下慢慢真的看懂] LEARN --> REAL[成为真正有价值的 Reviewer] REAL --> MENTOR[帮助下一个什么都不懂的新人] MENTOR --> START2[新人靠话术撑过最初几个月...] style START fill:#ff6b6b style FAKE fill:#ffd43b style REAL fill:#51cf66 style MENTOR fill:#74c0fc

Code Review 的话术,本质上是一种学习型假装——你用这些问题去探测代码的边界,在作者的回答里真正理解设计意图。每一个「边界场景怎么处理」的问题,背后都是你在建立自己的知识体系。

假装看懂是起点,不是终点。

如果三年后你还在用本文的话术,而没有进化成真正能看懂的那个人——那才是真正的放弃。


评论区
暂无评论
avatar