最近读《代码简洁之道》、《代码大全》和《编写可读代码的艺术》总结了一些通用的内容,作为团队代码的规范。
变量命名的目标
- 要完全、准确地描述出该变量所代表的事物
- 以问题为导向。一个好名字通常表达的是“什么”(what),而不是“如何”(why)
- 统一代码风格,降低代码的理解成本
变量名包含以下三类信息:
- 变量的内容(它代表什么)
- 数据的类型(具名常量、简单变量、用户自定义类型或者类)
- 变量的作用域(私有的、类的、包的或者全局的作用域)
通用原则
- 选择专业的词,避免使用“空洞”的词
1 | // 获取资源 |
避免像 temp 和 retval 这样泛泛的名字
- 好的名字应当描述变量的目的或者它所承载的值
1 | // Bad |
- 用具体的名字替代抽象的名字
- 使用能够读出来的名称。谨慎使用缩写或自造词,详细见缩写词的规范
1 | // Bad |
- 每个概念对应一个词,并一以贯之。 // 以同样的方式拼写出同样的概念才是信息;拼写前后不一致就是误导
1 | // Bad |
- 避免拼写错误 // 每个人都应该安装检查拼写的插件!!!
变量名的长度
最适当长度
- 建议长度:8 - 20 个字符的时候调试程序花费的力气最小 // 数据来源的论文写于还没有自动补全插件时代,可以不用太在意具体数字
- 如果自己的代码里发现很多更短的名字,需要确保这些名字含义是否清晰
- 由于编辑器的自动补全功能,输入长变量名已经不再是问题
- 一般来说,长的变量名由于便于搜索且信息更多会优于短的变量名。但是丢掉变量名中没用的词后,变短的变量名传递的信息并没有变少
变量名长度与作用域
名称长短应与其作用域大小相对应
单字母名称仅用于短方法中的本地变量,表示一个临时数据
对于全局命名空间的名词应该加以限定词,使之更明确
- Subsystem => UserInterfaceSubsystem
命名技巧
变量的数据类型应与变量名指向的类型一致
- 类名和对象名 => 名词或名词短语;不应该是动词
- 方法名 => 动词或动词短语
- 复数 => 数组
1 | // Bad |
添加有意义的语境
使用前缀或后缀来给名字附带更多信息
- i.e. firstName => addrFirstName
把变量作为类的成员字段,通过类来提供语境
- 现在 domain 里的属性、方法就拥有实体的语境
完善变量名的信息
- 如果关于一个变量有什么重要事情需要读者知道,那么值得把额外的“词”添加到名字中
- 如果变量是一个度量,最后在名字里带上它的单位
- 对于变量存在的危险或者意外,在任何时候都应在命名中附带这些重要属性
变量名中的计算值限定词
把限定词加到名字的最后,这样做的优点包括:
- 变量名中最重要的部分,即为这一变量赋予主要含义的部分应当位于最前面 => 确保最先被阅读到
- 避免由于同时在程序中使用不同规则而产生的歧义: totalRevenue vs revenueTotal
- 保证一组命名具有优雅的对称性: revenueTotal、revenueAverage、expenseTotal、expenseAverage
例外情况:Num 限定词
- Num 放在变量名的开始位置代表总数
- Num 放在变量名的结束位置代表一个下标
做有意义的区分
- 不应以数字系列命名: file1 和 file2
1 | // Bad |
不应在变量名中混入废话
- 如 variable 这个词永远不应该出现在变量名中
变量的不同之处放在开头或结尾,更易比较,不应放中间
1 | // 可以比较一下到底哪一种比较好 |
变量名中的常用对仗词
- 通过应用命名规则来提高对仗词使用的一致性,从而提高可读性
1 | - begin/end |
为特定类型的数据命名
为循环下标命名
循环中 i、j、k 这些名字都是约定俗成的
如果一个变量要在循环之外使用,那么就应该为它取一个比 i、j、k 更有意义的名字
如果循环不是只有几行,那么读者会容易忘记 i 本来具有的含义,最好给循环下标换一个更有意义的名字
如果使用了多个嵌套的循环,那么就应该给循环遍历赋予更长的名字以提高可读性。这样做的好处包括:
- 可以避免产生下标串话(index cross-talk)的场景问题
- 使得数据访问变得更加清晰:score[teamIndex][eventIndex] 比 score[i][j] 给出的信息更多
为状态变量命名
- 为状态变量取一个比 flag 更好的名字,因为看不出该标记是做什么的
- 标记应该使用枚举类型、具名常量
1 | // Bad |
为布尔值命名
典型的布尔变量名:
- done
- error
- found
- success 或 ok // 如果可以,应用更具体的名字替代 success,如 processingComplete
给布尔变量赋予隐含“真/假”含义的名字,用名词给布尔值命名就是很不好的例子
1 | // Bad |
使用肯定的布尔变量名
- 不要用 not、disable 开头
1 | // Bad |
- 加上 is、 has、 can、should、need 这样的词把布尔值变得更明确 // 该使用动词的单数还是复数形式取决于动作的主语
为枚举类型命名
- 使用枚举类型的时候,可以通过使用组前缀来明确表示改类型的成员都同属于一个组
为常量命名
- 根据该常量所表示的含义,而不是该常量所具有的数值为该抽象事物命名
为临时变量命名
- 临时性变量常被赋予 temp、x 或者其他一些模糊且缺乏描述性的名字
- 通常,临时变量是一个信号,表明程序员还没有完全把问题弄清楚
应该避免的命名方式
- 避免留下隐藏代码本意的错误线索
- 避免使用与本意相悖的词
- 避免将同一单词用于不同目的;遵从“一词一义”规则
- 避免使用令人误解的名字或缩写,确保名字的含义是明确的
- 避免使用具有相似含义的名字。如果能够交换两个边路的名字而不会妨碍对程序的理解,那么就需要为这两个变量重新命名了
- 避免使用具有不同含义但却有相似名字的变量
- 避免使用发音相近的名字: wrap 和 rap
- 避免使用英语中常常拼错的单词
- 不要仅靠大小写来区分变量名
- 避免使用多种自然语言,如不应混用 color 和 colour // 鱼塘全部使用美式英语
- 避免使用标准类型、变量和子程序的名字 // eslint 已经做了保留字检查
- 不要使用与变量含义完全无关的名字
- 避免在名字中包含易混淆的字符:数字1和小写字母l,数字1和大写字母I,数字0和字母O…
关于缩写
使用什么样的缩写?
- 使用标准的缩写(列在字典里的那些常见缩写)
- 缩写的标准:团队的新成员能否理解这个名字的含义,如果能, 你就没问题
1 | // Bad |
使用缩写的规则
- 不用使用语音缩写: skating => sk8ing
- 不用从每个单词中删除一个字符的方式来缩写
- 缩写要前后一致
- 创建你能读出来的名字,即不要只是按照字母挨个读出来
- 避免使用人员看错或者读错的组合
- 在代码里用缩写对照表解释极短的名字的含义
Reference:
- 代码大全
- 编写可读代码的艺术
- 代码简洁之道