停止编写“Clean”代码。开始编写可读代码。
Source: Dev.to
是的,这又是一篇关于整洁代码的文章。温馨提示: according to various sources,阅读代码所花费的时间与编写代码的时间比例可以达到 7:1,甚至更高。无论是修复 bug、添加功能还是重构,你不可避免地要沉浸在他人(或几个月前的自己)编写的逻辑中。这就是为什么可读性远比你最初敲代码的速度更为关键。
不可读的代码是技术债务,会成为整个团队的瓶颈,并在长期内推高开发成本。 句号。
可读代码的核心原则
我认为是时候认识到 “干净代码” 并不是灵丹妙药,也不是一套神圣、不可违背的法则。理想的代码并不存在,也不可能存在。它更像是一种哲学——一套帮助代码易于理解的建议。讽刺的是,这些“不可违背的法则”往往导致人们无法达成共识,引发无休止的争论和相互冲突的解释。
我不想把这篇文章变成另一篇“正确代码”的总结。如果你想写纯粹的学术代码(这本身就是不可能的),那就去阅读 Robert Martin 的 Clean Code 吧。本文提倡 理性整洁。在真正需要的地方使用它——也就是在需要维护的项目中。
“最好的代码是愚蠢地可读的代码。”
代码不应该让你的大脑必须费劲思考才能理解其意图。让我们一起走过这些基础,因为没有它们,可维护性 甚至不在讨论范围之内:
1. 清晰的变量和函数名
这句话已经被说了一千遍了,我还会再说第千零一次。它是绝对的基础。名字必须揭示意图。如果你看到一个名为 d 或 list1 的变量,你就得在天知道的地方搜寻,或深入实现细节才能弄清它到底是什么。如果它叫 elapsedTimeInDays 或 activeUsers,这些疑问就会消失。
2. 单一职责原则 (SRP)
一个函数应该只做 一件 事,并且把这件事做好。当你看到一个 handleUserData 函数既获取表单数据、又验证、再保存到数据库,还发送邮件——这就是红灯警告。我 可以 让你把它拆成 validateForm、saveUserToDatabase 和 sendWelcomeEmail,但真正让人警醒的是,你一开始就把所有这些功能塞进了同一个函数。如果你被一个庞大的单体应用束缚,这至少是可读性的基线。
3. 一致的编码风格
使用制表符还是空格并不重要(虽然制表符占用的内存更少,但谁在乎呢?),大括号放在哪里也不重要。重要的是整个团队以相同的方式编写代码。至少,别在“醉酒状态”下为处理 1 000 000 RPS 的微服务切换不同的范式。风格不一致会产生视觉噪音。幸运的是,lint 工具和格式化工具早已解决了这个问题。只需配置一次,让机器人来处理风格。
什么?代码审查?
代码审查并不是指责他人;它是促进集体成长的最有效工具之一。为了让审查有条不紊,记住以下检查清单:
| 区域 | 要提问的问题 |
|---|---|
| 逻辑 | 它是否解决了任务?是否处理了边缘情况? |
| 可读性 | 名称是否清晰?结构是否过于复杂? |
| 架构 | 它是否遵循项目模式?是否可扩展? |
| 测试 | 是否有测试?它们是否覆盖了“正常路径”和其他情况? |
| 自动化 | 让机器人来工作。对重复、潜在错误和漏洞的常规检查应交由自动化处理。像 SonarQube 这样的工具在你的 CI/CD 流水线中可以捕获约 90 % 的常见问题,甚至在人工审查之前。 |
| 教学 | 专注于教学,而不是批评。不要使用指令式的“修复此处”,而是采用对话方式:“如果我们尝试这种方法会怎样?我认为这可能会简化后期的维护。” 我们需要对同事——以及所有人——更友善。世界缺少善意。 |
Source: …
模式与反模式:用猫来解释
在编程中,就像和猫相处一样,既有优雅的解决方案,也有奇怪、纠结的烂摊子。有人会说,“这不就是《Clean Code》摘要吗!”其实不然。我在这里呼吁你立刻采取必要的措施。只要遵循下面的做法,未来的自己一定会感激你。
1. 深层嵌套(箭头代码)
反模式
if (catWantsToPlay) {
if (isLivingRoom) {
if (blanketOnCouch) {
if (boxUnderBlanket) {
if (catnipInBox) {
// Success, the cat is high!
}
}
}
}
}
金字塔式的缩进迫使你在脑中记住整条链路。
“提前返回”模式(守卫子句)
if (!catWantsToPlay) return;
if (!isLivingRoom) return;
if (!blanketOnCouch) return;
if (!boxUnderBlanket) return;
if (!catnipInBox) return;
// Success, the cat is high!
守卫子句把结构扁平化,使意图一目了然。
2. 神秘的猫行为
反模式
if (catState === 1) {
// Pet
} else if (catState === 2) {
// Feed
} else if (catState === 3) {
// Don't touch, the cat is dead
}
1、2、3 到底代表什么?这就是 魔法数字。今天你可能记得,但一个月后你可能要在文档(如果还有的话)里翻来覆去才能解读这段代码。
“具名常量”模式
const STATE_PURRING = 1;
const STATE_HUNGRY = 2;
const STATE_DEAD = 3;
if (catState === STATE_PURRING) {
// Pet
} else if (catState === STATE_HUNGRY) {
// Feed
} else if (catState === STATE_DEAD) {
// Don't touch
}
3. 为两只相同的猫喂食
反模式(复制粘贴)
// Feed Barsik
putInBowl("Barsik", "kibble");
pourInBowl("Barsik", "water");
callCat("Barsik");
// Feed Murzik
putInBowl("Murzik", "kibble");
pourInBowl("Murzik", "water");
callCat("Murzik");
如果要加维生素,你必须在两个地方都改代码。十只猫的情况下,你一定会忘记改某一只。
更好的做法(DRY)
function feedCat(catName) {
putInBowl(catName, "kibble");
pourInBowl(catName, "water");
callCat(catName);
}
feedCat("Barsik");
feedCat("Murzik");
警告: 请 不要 将此模式用于 不同 的用例。这是一种叫做 服务地狱 的反模式——在一个地方的错误可能导致其他地方出现莫名其妙的崩溃。每个用例都应当被隔离。
猫驱动项目的整洁代码
代码变得平坦而清晰——就像猫直奔目标的路径。
可读的代码和文档
好的代码是自解释的,但仍然需要注释来解释原因。如果你为外部库的 bug 使用了变通方法,请留下链接。否则你会在周五晚上收到一个“生产环境宕机”的惊讶电话。
写代码前先思考:代码会被更新,但人们常常害怕动旧的注释。不要过度。
实用技巧
- 微重构 – 看到不好的命名?改掉。函数做了所有事?把它拆分——但拆成逻辑块,而不是 3,000 个小碎片。让代码比你发现时更干净。就像在座位上捡起别人的垃圾。
- 结对编程 – 实时审查。是共享知识或辩论 QuickSort 与 MergeSort 速度的好方式。
- 内部指南 – 约定规则并坚持执行。偶尔真的看看,否则它们毫无用处。
务实至上
可读的代码加快开发速度。事实如此。但“干净代码”并非万灵药。每个人仍会争论“干净”到底意味着什么。如果任务不需要,别盲目追随任何大师。
如果你在编写一次性迁移脚本或明天就会被抛弃的原型,花几个小时去设计架构是适得其反的。上下文决定一切。
最糟糕的做法是机械地套用复杂模式,而简单的解决方案已经足够。三周后,你得到一个启动时间比运行时间还长的怪物,解决了根本不存在的问题。
目标不是为了“干净”而写干净代码,而是写可维护的代码,尤其在真正需要的地方。找到平衡,考虑项目的未来,并且始终保持学习。
(还有一点:永远不要与独裁政权合作。你构建的限制和系统正是让他们感到舒适并发动战争的根源。)
我说完了。祝你好运!

