代码命名规范

最近读《代码简洁之道》、《代码大全》和《编写可读代码的艺术》总结了一些通用的内容,作为团队代码的规范。

变量命名的目标

  • 要完全、准确地描述出该变量所代表的事物
  • 以问题为导向。一个好名字通常表达的是“什么”(what),而不是“如何”(why)
  • 统一代码风格,降低代码的理解成本

变量名包含以下三类信息:

  • 变量的内容(它代表什么)
  • 数据的类型(具名常量、简单变量、用户自定义类型或者类)
  • 变量的作用域(私有的、类的、包的或者全局的作用域)

通用原则

  • 选择专业的词,避免使用“空洞”的词
1
2
3
4
5
6
7
8
// 获取资源
// Bad
getxxx()
// Good
computexxx() // 计算得出
fetchxxx() // 通过网络请求获取
loadxxx() // 通过网络请求获取
downloadxxx() // 下载
  • 避免像 temp 和 retval 这样泛泛的名字

    • 好的名字应当描述变量的目的或者它所承载的值
1
2
3
// Bad
tmpCompensationBooks
tmpChannels
  • 用具体的名字替代抽象的名字
  • 使用能够读出来的名称。谨慎使用缩写或自造词,详细见缩写词的规范
1
2
// Bad
sv // specificationValue
  • 每个概念对应一个词,并一以贯之。 // 以同样的方式拼写出同样的概念才是信息;拼写前后不一致就是误导
1
2
// Bad
maxImagesCount + PicturesSection // 虽然 image 和 picture 都表示照片,但是应该前后统一
  • 避免拼写错误 // 每个人都应该安装检查拼写的插件!!!

变量名的长度

最适当长度

  • 建议长度:8 - 20 个字符的时候调试程序花费的力气最小 // 数据来源的论文写于还没有自动补全插件时代,可以不用太在意具体数字
  • 如果自己的代码里发现很多更短的名字,需要确保这些名字含义是否清晰
  • 由于编辑器的自动补全功能,输入长变量名已经不再是问题
  • 一般来说,长的变量名由于便于搜索且信息更多会优于短的变量名。但是丢掉变量名中没用的词后,变短的变量名传递的信息并没有变少

变量名长度与作用域

  • 名称长短应与其作用域大小相对应

    • 单字母名称仅用于短方法中的本地变量,表示一个临时数据

    • 对于全局命名空间的名词应该加以限定词,使之更明确

      • Subsystem => UserInterfaceSubsystem

命名技巧

变量的数据类型应与变量名指向的类型一致

  • 类名和对象名 => 名词或名词短语;不应该是动词
  • 方法名 => 动词或动词短语
  • 复数 => 数组
1
2
3
// Bad
workingStatus // 实际是数组
GeneralTraits // 实际是对象

添加有意义的语境

  • 使用前缀或后缀来给名字附带更多信息

    • i.e. firstName => addrFirstName
  • 把变量作为类的成员字段,通过类来提供语境

    • 现在 domain 里的属性、方法就拥有实体的语境

完善变量名的信息

  • 如果关于一个变量有什么重要事情需要读者知道,那么值得把额外的“词”添加到名字中
  • 如果变量是一个度量,最后在名字里带上它的单位
  • 对于变量存在的危险或者意外,在任何时候都应在命名中附带这些重要属性

变量名中的计算值限定词

  • 把限定词加到名字的最后,这样做的优点包括:

    1. 变量名中最重要的部分,即为这一变量赋予主要含义的部分应当位于最前面 => 确保最先被阅读到
    2. 避免由于同时在程序中使用不同规则而产生的歧义: totalRevenue vs revenueTotal
    3. 保证一组命名具有优雅的对称性: revenueTotal、revenueAverage、expenseTotal、expenseAverage
  • 例外情况:Num 限定词

    • Num 放在变量名的开始位置代表总数
    • Num 放在变量名的结束位置代表一个下标

做有意义的区分

  1. 不应以数字系列命名: file1 和 file2
1
2
3
4
5
// Bad
fields1
fields2
// Better
priceGroup // priceFields 可能会更好?
  1. 不应在变量名中混入废话

    1. 如 variable 这个词永远不应该出现在变量名中
  2. 变量的不同之处放在开头或结尾,更易比较,不应放中间

1
2
3
// 可以比较一下到底哪一种比较好
warehouseItemFromSource vs sourceWarehouseItem
userItemFromTarget vs targetUserItem

变量名中的常用对仗词

  • 通过应用命名规则来提高对仗词使用的一致性,从而提高可读性
1
2
3
4
5
6
7
8
9
10
11
- begin/end
- first/last
- locked/unlocked
- min/max
- next/previous
- old/new
- opened/closed
- visible/invisible
- source/target
- source/destination
- up/down

为特定类型的数据命名

为循环下标命名

  • 循环中 i、j、k 这些名字都是约定俗成的

  • 如果一个变量要在循环之外使用,那么就应该为它取一个比 i、j、k 更有意义的名字

  • 如果循环不是只有几行,那么读者会容易忘记 i 本来具有的含义,最好给循环下标换一个更有意义的名字

  • 如果使用了多个嵌套的循环,那么就应该给循环遍历赋予更长的名字以提高可读性。这样做的好处包括:

    • 可以避免产生下标串话(index cross-talk)的场景问题
    • 使得数据访问变得更加清晰:score[teamIndex][eventIndex] 比 score[i][j] 给出的信息更多

为状态变量命名

  • 为状态变量取一个比 flag 更好的名字,因为看不出该标记是做什么的
  • 标记应该使用枚举类型、具名常量
1
2
3
4
// Bad
PackageBase {
flags: ...
}

为布尔值命名

  • 典型的布尔变量名:

    • done
    • error
    • found
    • success 或 ok // 如果可以,应用更具体的名字替代 success,如 processingComplete
  • 给布尔变量赋予隐含“真/假”含义的名字,用名词给布尔值命名就是很不好的例子

1
2
3
4
// Bad
status // status 没有指向任何是否类的结果
// Good
Done // 词汇本身具有是否类的指向
  • 使用肯定的布尔变量名

    • 不要用 not、disable 开头
1
2
3
4
5
// Bad
notActive // 在判断取反的时候会增加理解成本,如 if(!notActive)
disableActing
// Good
active
  • 加上 is、 has、 can、should、need 这样的词把布尔值变得更明确 // 该使用动词的单数还是复数形式取决于动作的主语

为枚举类型命名

  • 使用枚举类型的时候,可以通过使用组前缀来明确表示改类型的成员都同属于一个组

为常量命名

  • 根据该常量所表示的含义,而不是该常量所具有的数值为该抽象事物命名

为临时变量命名

  • 临时性变量常被赋予 temp、x 或者其他一些模糊且缺乏描述性的名字
  • 通常,临时变量是一个信号,表明程序员还没有完全把问题弄清楚

应该避免的命名方式

  • 避免留下隐藏代码本意的错误线索
  • 避免使用与本意相悖的词
  • 避免将同一单词用于不同目的;遵从“一词一义”规则
  • 避免使用令人误解的名字或缩写,确保名字的含义是明确的
  • 避免使用具有相似含义的名字。如果能够交换两个边路的名字而不会妨碍对程序的理解,那么就需要为这两个变量重新命名了
  • 避免使用具有不同含义但却有相似名字的变量
  • 避免使用发音相近的名字: wrap 和 rap
  • 避免使用英语中常常拼错的单词
  • 不要仅靠大小写来区分变量名
  • 避免使用多种自然语言,如不应混用 color 和 colour // 鱼塘全部使用美式英语
  • 避免使用标准类型、变量和子程序的名字 // eslint 已经做了保留字检查
  • 不要使用与变量含义完全无关的名字
  • 避免在名字中包含易混淆的字符:数字1和小写字母l,数字1和大写字母I,数字0和字母O…

关于缩写

使用什么样的缩写?

  • 使用标准的缩写(列在字典里的那些常见缩写)
  • 缩写的标准:团队的新成员能否理解这个名字的含义,如果能, 你就没问题
1
2
// Bad
itemcat 类目

使用缩写的规则

  • 不用使用语音缩写: skating => sk8ing
  • 不用从每个单词中删除一个字符的方式来缩写
  • 缩写要前后一致
  • 创建你能读出来的名字,即不要只是按照字母挨个读出来
  • 避免使用人员看错或者读错的组合
  • 在代码里用缩写对照表解释极短的名字的含义

Reference:

  • 代码大全
  • 编写可读代码的艺术
  • 代码简洁之道