停止编写“Clean”代码。开始编写可读代码。

发布: (2026年2月15日 GMT+8 14:36)
11 分钟阅读
原文: Dev.to

Source: Dev.to

Clean Code illustration

是的,这又是一篇关于整洁代码的文章。温馨提示: according to various sources,阅读代码所花费的时间与编写代码的时间比例可以达到 7:1,甚至更高。无论是修复 bug、添加功能还是重构,你不可避免地要沉浸在他人(或几个月前的自己)编写的逻辑中。这就是为什么可读性远比你最初敲代码的速度更为关键。

不可读的代码是技术债务,会成为整个团队的瓶颈,并在长期内推高开发成本。 句号。

可读代码的核心原则

我认为是时候认识到 “干净代码” 并不是灵丹妙药,也不是一套神圣、不可违背的法则。理想的代码并不存在,也不可能存在。它更像是一种哲学——一套帮助代码易于理解的建议。讽刺的是,这些“不可违背的法则”往往导致人们无法达成共识,引发无休止的争论和相互冲突的解释。

我不想把这篇文章变成另一篇“正确代码”的总结。如果你想写纯粹的学术代码(这本身就是不可能的),那就去阅读 Robert Martin 的 Clean Code 吧。本文提倡 理性整洁。在真正需要的地方使用它——也就是在需要维护的项目中。

“最好的代码是愚蠢地可读的代码。”

代码不应该让你的大脑必须费劲思考才能理解其意图。让我们一起走过这些基础,因为没有它们,可维护性 甚至不在讨论范围之内:

1. 清晰的变量和函数名

这句话已经被说了一千遍了,我还会再说第千零一次。它是绝对的基础。名字必须揭示意图。如果你看到一个名为 dlist1 的变量,你就得在天知道的地方搜寻,或深入实现细节才能弄清它到底是什么。如果它叫 elapsedTimeInDaysactiveUsers,这些疑问就会消失。

2. 单一职责原则 (SRP)

一个函数应该只做 一件 事,并且把这件事做好。当你看到一个 handleUserData 函数既获取表单数据、又验证、再保存到数据库,还发送邮件——这就是红灯警告。我 可以 让你把它拆成 validateFormsaveUserToDatabasesendWelcomeEmail,但真正让人警醒的是,你一开始就把所有这些功能塞进了同一个函数。如果你被一个庞大的单体应用束缚,这至少是可读性的基线。

3. 一致的编码风格

使用制表符还是空格并不重要(虽然制表符占用的内存更少,但谁在乎呢?),大括号放在哪里也不重要。重要的是整个团队以相同的方式编写代码。至少,别在“醉酒状态”下为处理 1 000 000 RPS 的微服务切换不同的范式。风格不一致会产生视觉噪音。幸运的是,lint 工具和格式化工具早已解决了这个问题。只需配置一次,让机器人来处理风格。

什么?代码审查?

代码审查并不是指责他人;它是促进集体成长的最有效工具之一。为了让审查有条不紊,记住以下检查清单:

区域要提问的问题
逻辑它是否解决了任务?是否处理了边缘情况?
可读性名称是否清晰?结构是否过于复杂?
架构它是否遵循项目模式?是否可扩展?
测试是否有测试?它们是否覆盖了“正常路径”和其他情况?
自动化让机器人来工作。对重复、潜在错误和漏洞的常规检查应交由自动化处理。像 SonarQube 这样的工具在你的 CI/CD 流水线中可以捕获约 90 % 的常见问题,甚至在人工审查之前。
教学专注于教学,而不是批评。不要使用指令式的“修复此处”,而是采用对话方式:“如果我们尝试这种方法会怎样?我认为这可能会简化后期的维护。” 我们需要对同事——以及所有人——更友善。世界缺少善意。

Source:

模式与反模式:用猫来解释

Cats and code

在编程中,就像和猫相处一样,既有优雅的解决方案,也有奇怪、纠结的烂摊子。有人会说,“这不就是《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
}

123 到底代表什么?这就是 魔法数字。今天你可能记得,但一个月后你可能要在文档(如果还有的话)里翻来覆去才能解读这段代码。

“具名常量”模式

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 速度的好方式。
  • 内部指南 – 约定规则并坚持执行。偶尔真的看看,否则它们毫无用处。

务实至上

可读的代码加快开发速度。事实如此。但“干净代码”并非万灵药。每个人仍会争论“干净”到底意味着什么。如果任务不需要,别盲目追随任何大师。

如果你在编写一次性迁移脚本或明天就会被抛弃的原型,花几个小时去设计架构是适得其反的。上下文决定一切。

最糟糕的做法是机械地套用复杂模式,而简单的解决方案已经足够。三周后,你得到一个启动时间比运行时间还长的怪物,解决了根本不存在的问题。

目标不是为了“干净”而写干净代码,而是写可维护的代码,尤其在真正需要的地方。找到平衡,考虑项目的未来,并且始终保持学习。

(还有一点:永远不要与独裁政权合作。你构建的限制和系统正是让他们感到舒适并发动战争的根源。)

我说完了。祝你好运!

0 浏览
Back to Blog

相关文章

阅读更多 »