Skip to content

命名与语义:代码中的语言哲学 (The Art of Naming & Semantics) ​

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton

在软件工程的浩瀚宇宙中,我们花费了大量时间争论架构模式、数据库选型和语言优劣。然而,真正占据我们日常 90% 认知带宽的,往往是那些最微小的细节:变量名、函数名、类名。

命名不仅仅是一个标签,它是思维的投影。一个糟糕的名字不仅仅是难看,它是一个谎言,一个误导读者的路标,一个增加系统熵增的罪魁祸首。

本章将探讨命名的哲学本质,以及如何通过精准的语义来降低系统的认知负荷。


1. 命名的第一性原理:代码是写给人看的 ​

计算机并不在乎你把变量叫 x 还是 customerBalance。对于 CPU 而言,它们只是内存地址的偏移量。

命名的唯一目的是沟通。

当我们写下代码时,我们实际上是在进行双重创作:

  1. 给机器的指令:定义程序的行为。
  2. 给人类的文档:定义程序的意图。

在现代软件工程中,第二点的价值远远超过第一点。代码被阅读的次数是它被编写次数的 10 倍以上。如果你的名字需要读者去"推断"或"猜测",你就失败了。

认知负荷 (Cognitive Load) ​

每一个模糊的名字都是一笔认知债务。 当读者看到 data、handle() 或 process() 时,他们的大脑必须暂停,去查看上下文,去阅读实现细节,才能在脑海中构建出"这到底是什么"的模型。

  • 好名字:让读者在不看实现的情况下理解意图(Deep Module Interface)。
  • 坏名字:迫使读者必须阅读实现才能理解意图(Leaky Abstraction)。

2. 通用语言 (Ubiquitous Language) ​

领域驱动设计 (DDD) 提出了一个核心概念:通用语言。

代码中的术语必须与业务专家的术语保持严格一致。如果业务方称之为 "Order"(订单),而你在代码里叫它 "Transaction"(交易),你就制造了一个翻译层。

这个翻译层是 Bug 的温床。

  • 反模式:开发者方言。
    • UserUploadManager (技术视角的命名)
    • OrderProcessor (毫无意义的后缀)
  • 正模式:领域视角的命名。
    • DocumentRepository
    • OrderFulfillment

规则:如果业务专家看不懂你的类名,说明你的抽象可能错了。


3. 语义的精度:拒绝模糊 ​

模糊是清晰的大敌。我们经常使用一些"万能词汇"来逃避思考。

警惕 "Manager", "Processor", "Handler" ​

这些后缀通常是"我不知道这个类该干什么,反正它负责处理这堆东西"的代名词。

  • OrderManager -> 是负责创建订单?(OrderFactory) 还是负责保存订单?(OrderRepository) 还是负责发货?(ShippingService)
  • 重构建议:试着去掉后缀,如果名字变得不通顺,说明这个类的职责定义不清。

警惕 "Data", "Info", "Item" ​

  • UserData -> 和 User 有什么区别?
  • ProductInfo -> 和 Product 有什么区别? 除非你有明确的架构分层定义(如 DTO),否则不要随意添加这些无意义的后缀。

动词的精确性 ​

  • get():通常暗示轻量级的内存读取。如果这个操作涉及昂贵的数据库查询,请改用 fetch() 或 retrieve()。
  • create():通常暗示在内存中构建对象。如果这个操作会立即持久化到数据库,请考虑 save() 或 persist()。

4. 上下文决定语义 (Bounded Context) ​

同一个单词在不同上下文中含义完全不同。

  • Context A (电商销售): Book 可能意味着 ISBN、标题、价格、作者。
  • Context B (仓储物流): Book 可能意味着 长、宽、高、重量、库存位置。
  • Context C (电子书阅读器): Book 可能意味着 文本内容、字体大小、阅读进度。

试图创建一个包含所有这些属性的上帝类 Book 是灾难性的。 好的命名应当限定在特定的限界上下文 (Bounded Context) 中。


5. 命名的反直觉真理 ​

名字越短,作用域越小 ​

  • 在 3 行的 for 循环中,i 是完美的命名。
  • 在 500 行的类中,i 是灾难。
  • 全局变量必须有极度详细的描述性命名。

好的命名不需要注释 ​

如果你觉得需要写一行注释来解释变量是什么,请先尝试重命名这个变量。

javascript
// Bad
// check if user is allowed
if (user.flag & 0x4) { ... }

// Good
if (user.isAdministrator()) { ... }

对称性 ​

命名应当展现出对称的美感,这有助于读者的预测。

  • add/remove
  • insert/delete
  • start/stop
  • begin/end
  • send/receive
  • get/set

不要混用,例如 add/delete 或 begin/stop,这会破坏认知预期。


6. 实战演练:重构命名 ​

案例 1:布尔值 ​

Bad: status, flag, validGood: isOpen, hasAccess, isValid布尔变量应始终读起来像是一个是非问句(Is, Has, Can, Should)。

案例 2:集合 ​

Bad: userList, uArrGood: users, activeUsers不要把类型(List, Array)编码进名字,除非那是核心语义。

案例 3:魔法数字 ​

Bad: if (order.status === 3) ...Good: if (order.status === OrderStatus.SHIPPED) ...给每一个魔法数字一个名字,就是给它赋予了灵魂。


结语:命名即设计 ​

当你发现很难给一个类或函数命名时,通常不是因为你词汇量不够,而是因为设计有问题。

  • 如果名字需要用 And 连接(例如 UserValidatorAndEmailSender),说明它违反了单一职责原则 (SRP)。
  • 如果名字极其抽象(例如 ObjectManager),说明你没有想清楚它的具体职责。

命名是设计的试金石。 在写代码之前,先在脑海中推演名字,这往往能帮你通过最低的成本发现架构上的漏洞。

"Names are the hooks on which we hang our understanding."

由 VitePress 构建,Markdown 教材原地维护。