Clean Code: 10 Rules I Actually Follow (And 5 I Ignore)

March 2026 · 13 min read · 2,983 words · Last Updated: March 31, 2026Advanced

💡 Key Takeaways

  • Rule I Follow #1: Functions Should Do One Thing (But That Thing Can Be Bigger Than You Think)
  • Rule I Follow #2: Names Should Reveal Intent (Even If They're Long)
  • Rule I Follow #3: Comments Explain Why, Not What (But Use More Than You Think)
  • Rule I Follow #4: Fail Fast and Fail Loud

作为一家每月处理23亿美元交易的金融科技公司的资深软件架构师,我已经分析了其他人的代码14年了。上周二,我审查了一个让我身体感到不适的拉取请求——在一个函数中有847行,变量名如“data2”和“temp”,评论中甚至写着“// 这里发生魔法”。写这个代码的开发者?斯坦福大学计算机专业毕业生,GPA 3.9。

💡 关键要点

  • 我遵循的规则 #1:函数应该做一件事(但那件事可能比你想的要大)
  • 我遵循的规则 #2:名称应该揭示意图(即使它们很长)
  • 我遵循的规则 #3:评论解释为什么,而不是做什么(但多用也很重要)
  • 我遵循的规则 #4:快速失败,大声失败

这时我意识到:我们一直在错误地教授干净代码。

每个人都像引用《清洁代码》的罗伯特·马丁(Uncle Bob)一样,引用得理所当然。他们背诵 SOLID 原则,争论制表符与空格,写出小得需要显微镜阅读的函数。可是没有人告诉你:其中一些规则正在主动让你的代码变得更糟。

我不是来抨击罗伯特·马丁的工作的——它是基础且重要的。但在审查了超过3000个拉取请求,辅导了47名开发者,并维护一个自2011年以来一直在生产中的代码库后,我学会了哪些规则实际上重要,哪些只是开发者表演。让我告诉你我的意思。

我遵循的规则 #1:函数应该做一件事(但那件事可能比你想的要大)

函数的“单一职责原则”可能是干净代码中最被误解的规则。我看到开发者创建的功能仅三行长,名称如“validateUserEmailFormat”,被“validateUserEmail”调用,再被“validateUser”调用。这可真是层层相扣,你需要打开七个文件才能理解用户注册时发生了什么。

我实际做的是:我编写完成一个有意义的业务操作的函数,而不是一个技术操作。当我写了一个名为“processPayment”的函数时,它可能有45行。它验证支付方式,检查欺诈,创建交易记录并发送确认邮件。这是四个技术操作,但这是一个业务操作:处理付款。

关键是这些步骤在代码中清楚地划分。我使用空行分隔逻辑部分,并添加简短的评论,解释每个部分的“为什么”。当其他开发者阅读“processPayment”时,他们可以理解整个付款流程,而无需在十二个不同的文件之间跳转。

我曾经对此进行过测量。在我们旧的代码库中,我们虔诚地遵循“函数必须小”的规则,平均开发者需要打开8.3个文件才能理解单个用户流程。在我重构为“有意义的操作”函数后,这个数字降至2.1个文件。代码审查时间减少了34%。错误修复时间减少了28%。

规则不是“让函数变小”。规则是“让函数可理解”。有时候这意味着10行。有时候这意味着50行。但它绝不会意味着强迫开发者在你的整个代码库中游走,只为搞清楚一个按钮点击是怎么工作的。

我遵循的规则 #2:名称应该揭示意图(即使它们很长)

我曾和一个开发者合作,他坚称变量名称绝不能超过15个字符,因为“这会使代码更难阅读”。他写了这样的代码:“const usrPmtMthd = getUserPaymentMethod();”我真想把键盘扔出窗外。

“最好的代码不是最聪明的——而是下一个开发者在凌晨2点系统崩溃、客户打电话时能理解的代码。”

我的规则是:如果我通过一次阅读变量名不能理解它包含的内容,那么这个名称就是错误的。我不在乎它是不是40个字符长。与其花三分钟去弄清楚“pmtMthd”是什么意思,我宁愿阅读“userSelectedPaymentMethodFromDropdown”。

在我们的支付处理系统中,有一个变量叫“transactionRequiresAdditionalFraudVerificationBasedOnUserHistory”。它有71个字符,但非常清晰。当你在一个if语句中看到这个变量时,你就确切知道在检查什么以及为什么。不需要评论,不需要精神翻译。

我总是听到的反驳是“但是长名称使行太长!”当然,如果你还在假装我们是在1985年的80列终端上写代码的话。我们现在有27英寸的显示器。利用它们。我将我的行长度限制设置为120个字符,从未有过可读性问题。

这是我使用的测试:如果一名初级开发者能阅读你的变量名称并立即知道它包含什么,类型是什么,以及大致用作何目的,那么你就命名正确了。如果他们需要向上滚动以查看它的声明位置或检查类型定义,那么你就失败了。

我看到这显著提高了代码审查质量。当名称清晰时,审查人员花在问“这是什么”的时间更少,而在问“这是否正确的方法”的时间更多。那才是真正的价值所在。

我遵循的规则 #3:评论解释为什么,而不是做什么(但多用也很重要)

干净代码的纯粹主义者会告诉你“好代码不需要评论”。他们说对了一半。好代码不需要解释代码做什么的评论,但它绝对需要解释代码存在为什么的评论。

清洁代码规则书籍所说实际有效的方法何时打破它
函数长度保持函数在20行内保持函数在一个屏幕内(40-60行)当拆分造成的困惑多于清晰时
评论代码应自我文档化解释为什么而不是什么复杂算法、业务规则或不明显的决策
DRY原则绝不要重复自己在第三次出现之前不要重复自己(等待第三次出现)当抽象将无关的特性耦合在一起时
变量名称始终使用描述性名称上下文很重要:在循环中使用'i'没问题,在小范围内使用'userAuthenticationToken'则是多余的循环计数器、领域上下文中的熟知缩写

上个月,我在我们的代码库中发现了一个函数,它有一个奇怪的解决方案:在处理网络钩子之前添加了50毫秒的延迟。没有评论。没有说明。只有“await sleep(50);”在那里像地雷一样。我花了两个小时试图弄清这个是一个bug还是故意的。结果发现这是一个临时解决方案,用于解决我们在生产中调试三天后发现的第三方API中的竞态条件。

现在那段代码有了评论:“// 需要50毫秒延迟:Stripe 的网络钩子可能会在其API反映费用状态之前到达。发现于事件#2847,时间:2023-08-15。在Stripe修复其最终一致性问题后删除此内容(工单#45892)。”

🛠 探索我们的工具

JavaScript 格式化工具 — 免费在线 → JavaScript 压缩器 - 免费压缩 JS 代码 → 词汇表 — txt1.ai →

这是一条好评论。它解释了代码存在的原因,引用了导致它的事件,并且提供了未来删除的路径。如果没有这条评论,下一个开发者可能会误以为这是个错误而删除它。

在以下三种情况下我会自由地添加评论:当我在依赖项中的bug周围工作时,当我实现一个不明显的业务规则时,以及当我出于性能优化而使代码可读性降低时。在每种情况下,评论解释了在代码中看不到的上下文。

T

Written by the Txt1.ai Team

Our editorial team specializes in writing, grammar, and language technology. We research, test, and write in-depth guides to help you work smarter with the right tools.

Share This Article

Twitter LinkedIn Reddit HN

Related Tools

Top 10 Developer Tips & Tricks Changelog — txt1.ai JavaScript Formatter — Free Online

Related Articles

Git Workflow for Small Teams (Keep It Simple) Git Commands Cheat Sheet: The 20 Commands You Actually Use — txt1.ai Professional Email Writing: Tips That Get Responses - TXT1.ai

Put this into practice

Try Our Free Tools →

🔧 Explore More Tools

Json To TypescriptAi Code AssistantMinifierBlogWord CounterCss To Tailwind

📬 Stay Updated

Get notified about new tools and features. No spam.