1. 命名的重要性

命名是开发中最基础、最频繁的工作之一。无论是类名、方法名、变量名还是常量名,每一个名称都承载着代码的意图。一个差的命名会让代码变得难以理解,而一个清晰的命名则能让代码自解释,大大提升可维护性。

想象一下,你看到如下代码:

function applies(e: Evnt) {
    if (e.d == 6 || e.d == 0) {
         return false;
    } else {
        return (e.t.h >= 8 && e.t.h < 18); 
    }
}

你能一眼看出这段代码的用途吗?虽然逻辑简单,但意图不明。现在我们换一个命名更清晰的版本:

function isDuringWorkingHours(event: Event) {
    if (event.dayOfWeek == DayOfWeek.SATURDAY || event.dayOfWeek == DayOfWeek.SUNDAY) {
         return false;
    } else {
        return (event.time.hour >= WORKING_DAY_START && event.time.hour < WORKING_DAY_END); 
    }
}

是不是立刻明白了它的作用?这就是命名的力量。


2. 命名的目标

命名的核心目标是帮助代码讲述它的故事。代码的读者不仅是机器,更是人,尤其是其他开发者。一个项目在其生命周期中可能会经历多次人员更替,因此我们命名时必须考虑以下几点:

  • 清晰易懂:一看就知道是干什么的
  • 减少歧义:避免让读者产生误解
  • 跨文化友好:不使用特定文化背景才懂的词汇

尤其在多人协作或长期维护的项目中,良好的命名习惯能极大降低沟通成本和学习曲线。


3. 命名的原则

3.1. 遵循最小意外原则(Principle of Least Surprise)

命名要符合读者的预期。比如:

  • 类名用名词(如 UserService
  • 方法名用动词或动词短语(如 sendEmail()calculateTax()

这样其他开发者在阅读代码时不会感到困惑,也能更快找到他们需要的逻辑。

3.2. 可搜索性强

短命名(如 i, d, t)虽然节省字符,但不利于搜索和理解。例如:

int d = 5;

搜索 d 会匹配成百上千个结果。但如果写成:

int dayOfWeek = 5;

搜索时就非常精准,也容易理解。

3.3. 一个概念,一个词

对于同一个概念,保持命名一致性。比如:

  • 如果一个字段叫 address,那么所有类似字段都应使用 address
  • 如果一个方法叫 calculateTax(),那么其他类似操作也应使用 calculateXxx() 的形式

但注意:不同概念不能共享一个词。例如,match() 可以表示“匹配”、“比赛”或“火柴”,在不同上下文中要区分开。

3.4. 发音友好

命名要考虑口头交流的便利性。如果别人问你:“这个 usrNm 是干嘛的?”你可能会一脸懵。但如果是 userName,大家都能轻松理解和讨论。

3.5. 遵循命名规范

  • 类名:大驼峰(PascalCase)UserService
  • 方法名、变量名:小驼峰(camelCase)getUserName()
  • 常量名:全大写+下划线 MAX_RETRY_COUNT

4. 命名应避免的做法

4.1. 不准确的信息(Disinformation)

命名要准确反映其内容。例如:

Set<Address> addressList = person.getAddresses();

变量名是 addressList,但实际是 Set,这容易误导开发者。更合适的命名是:

Set<Address> addresses = person.getAddresses();

另外,避免使用无意义的“噪音词”如 data, info, manager, processor 等,除非它们确实有明确语义。

4.2. 避免编码式命名(Hungarian Notation)

现代IDE已经能自动识别类型,没必要在变量名中加上类型信息,比如:

❌ 不推荐:

String strName = "John";

✅ 推荐:

String name = "John";

4.3. 避免俚语或玩笑

虽然 buttonSmashHandler() 看起来挺酷,但在正式项目中还是用 buttonClickHandler() 更合适。代码不是段子,清晰比幽默更重要。

4.4. 避免心智映射(Mental Mapping)

单字母变量如 i, j 可用于循环计数器,但在其他场景下应避免使用,例如:

❌ 不推荐:

int x = calculate(y);

✅ 推荐:

int taxAmount = calculateTax(income);

4.5. 同名但不同义(One Word – Different Meaning)

如前所述,一个词只能表示一个概念。例如:

  • match() 用于匹配字符串
  • match() 用于比赛结果
  • match() 用于火柴

这种歧义容易引发错误,应根据上下文使用不同的命名,如 findMatch(), startGame(), igniteMatch()

4.6. 命名不应依赖注释

命名本身就应该清晰到不需要注释来解释。比如:

❌ 不推荐:

int timeout = 5; // timeout in seconds

✅ 推荐:

int timeoutInSeconds = 5;

4.7. 慎用缩写(Acronyms)

缩写可以节省字符,但容易引起误解。例如:

  • ID 可能代表“身份标识”或“内径(Inside Diameter)”
  • DB 可能是“数据库”或“分贝”

除非缩写非常通用(如 URL, HTTP),否则建议写出全称:

✅ 推荐:

String userId = "U123456";

5. 总结

命名是编写整洁代码的关键环节。一个好名字可以让代码更易读、更易维护,也能减少沟通成本。本文总结了命名的几个核心原则:

清晰表达意图
遵循最小意外原则
保持一致性
可搜索性强
避免误导和噪音词
不依赖注释

同时,也列出了常见的命名误区,如使用俚语、编码式命名、心智映射等。希望这些原则能帮助你在日常开发中写出更清晰、更专业的代码。


原始标题:Clean Code: Naming