为什么你的代码能运行却仍然在 Code Review 中被拒绝

发布: (2026年2月26日 GMT+8 09:10)
8 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本内容,我将按照要求保留源链接并仅翻译正文部分。谢谢!

你是否曾经提交过一个所有测试都通过、功能完美运行的 Pull Request,却在代码审查时收到 “Request Changes”(请求更改)的鲜红标记?

是的,我也有过这种经历。这让人沮丧,因为你会想,“但它 能工作!”

代码能够运行只是最低要求,并不是终点。

让我们来聊聊那些没人告诉你的代码审查隐藏规则。

1. 认知负荷

你的代码不会只被阅读一次。它在整个生命周期中会被 数百次 阅读。每当有人调试问题、添加功能或试图理解系统工作原理时,都会在阅读你的代码。

不佳示例

d = datetime.now()
y = d.year
m = d.month
dy = d.day

这段代码能运行,测试也通过,但每个阅读者都必须在脑中解码每个变量的含义。这就增加了认知负荷。

更佳示例

today = datetime.now()
year = today.year
month = today.month
day = today.day

它是自解释的。阅读者可以立刻理解意图,然后继续关注实际逻辑。

好代码 不会让你因为写了它而感到聪明。好代码会让下一个阅读它的人感到聪明。

2. 过早抽象

哦天,我也曾犯过这个错误。你对设计模式感到兴奋,结果突然间为一个每天只运行一次的功能构建了 DataProcessorFactoryProcessorRegistry 以及策略模式。

有一个原则叫 YAGNI —— You Aren’t Gonna Need It(你不会需要它)。

抽象很强大,但它也有代价:

  • 每一层抽象都是 bug 可能隐藏的地方。
  • 每一个接口都是未来开发者需要理解的额外内容。

经验法则: 在拥有至少 三个 具体的模式实例之前不要抽象。两个只是巧合,三个才算是模式。

3. 缺少 “为什么”

注释应该解释 WHY(为什么),而不是 WHAT(做了什么)。代码已经说明了你在做什么。

// convert to milliseconds
return seconds * 1000;

这条注释没有任何价值——代码已经表明这是一次单位转换。

// API times out after 5 seconds, so we use 4.5 s to leave a buffer
return seconds * 4500;

现在你记录了业务逻辑,解释了为什么这个特定的数字很重要。

同理适用于重试逻辑

// BAD: "Retry 3 times" is obvious from the code.
// GOOD: Third‑party API occasionally fails with 503 errors;
// retrying usually succeeds within 3 attempts.
for (let i

初级开发者 思考 应该 发生什么。
高级开发者 思考 可能 发生什么。

7. 魔法数字

50 是什么意思?300000 是什么意思?0.0 是什么意思?

(你的原始内容在此截断——请确保用具名常量或配置值替代魔法数字,并添加解释其用途的注释。)

想要更多真实生产环境的技巧吗?

在我的 YouTube 频道获取 25 年 的生产级经验:🛠️👉

0.75 是什么意思?

if (users.length > 50) paginate();
setTimeout(retry, 300000);
if (score > 0.75) approve();

这些数字现在对你可能有意义,但对其他人毫无意义——而且三个月后对你来说也会失去意义。

使用具名常量

const MAX_USERS_PER_PAGE = 50;
const RETRY_DELAY_MS = 300_000; // 5 minutes
const SUCCESS_THRESHOLD = 0.75;

MAX_USERS_PER_PAGE 传达了一个含义。当产品经理要求你修改阈值时,你希望能够快速定位并自信地进行更改。具名常量使这成为可能。

8. 测试捷径

测试通过,但它们真的测试了什么吗?

expect(result).toBeTruthy();

只要函数返回 1true"hello" 或任何非 falsy 值,这个测试就会通过。它并没有告诉你代码是否真的工作正常。

好的测试验证 特定行为

expect(result.email).toBe("user@example.com");
expect(result.name).toBe("Jane Doe");
expect(result.id).toBeDefined();

它们记录了代码应该做什么。它们让你在重构时有信心没有破坏任何功能。你的测试是给未来开发者的文档——让它们发挥作用。

代码审查的真正目标

代码审查并不主要是为了找 bug。现代测试已经捕获了大部分 bug。

代码审查的核心是 知识共享。它关系到代码质量的长期维护。它用于捕获边缘情况并确保代码的可维护性。

当审查者让你修改某些内容时,他们并不是在说你的代码不能工作。他们的意思是:

  • “如果我们这样做,后续维护会更容易”
  • “这更符合我们的模式”
  • “将来的你会感谢我们提供的清晰度。”

在提交下一个 PR 之前,问问自己:

  • 六个月后,当上下文已经淡化,是否还有人能理解这段代码?
  • 它是否遵循了团队的约定和模式?
  • 它是否已经尽可能简单,但不再简化?
  • 它是否能够优雅地处理错误?

能够运行的代码是最低门槛,而不是终点。优秀的代码是会“消失”的代码——代码如此清晰、结构如此良好,以至于后来的开发者几乎没有注意到它的存在,只是直接理解并继续工作。

你写代码不是给电脑看的。电脑并不在乎你的变量是 x 还是 userAccountBalance。你写代码是给人看的。

为凌晨 2 点疲惫的开发者写代码,让他们能够修复生产环境的 bug。为新加入的团队成员写代码,让他们能够快速了解系统是如何运作的。为六个月后已经忘记细节的自己写代码。

什么样的代码审查反馈最让你感到沮丧?在下方评论区告诉我们吧。

注意: 本文在 AI 的帮助下撰写,以帮助结构化和表达 25 年以上的调试经验。所有示例、洞见和方法论均来源于真实的实践经验。

0 浏览
Back to Blog

相关文章

阅读更多 »