代码简洁之道:我们该如何规范代码的命名?
代码简洁之道:我们该如何规范代码的命名?
在编程的世界里,代码命名不仅仅是给变量、函数和类起个名字那么简单。它关乎代码的可读性、可维护性和团队协作效率。本文将深入探讨各种命名方法的优劣,并提供实用的命名建议,帮助开发者写出更高质量的代码。
前言
著名软件工程师Phil Karlton曾说过:“计算机科学中只有两个难题:缓存失效和命名。”这句话道出了代码命名的重要性。在日常开发中,我们常常会遇到这样的困惑:如何给函数起一个既便于自己后续操作,又能让他人一看就懂的名字?这看似简单的任务,实际上蕴含着深刻的学问。
我们知道,命名的目的是为了方便人和计算机的理解,因此可以说命名实际上也是注释的一种,它和代码中的//
后的注释同样重要。一个好的命名可以让读者一眼就明白代码的意图。例如,假设我们需要为一个链表删除操作的函数命名,以下是三个备选方案:
A. DelLT
B. DeleteLinkLIst
C. DelLinkList
让我们分析一下:首先,我们需要完成删除操作,因此需要使用"Delete"这个动词;其次,这个操作是针对链表的,因此需要包含表示链表的名词。可见,函数命名需要同时表达这两个基本含义。接下来,我们将介绍几种常见的命名方法。
常见命名方法
匈牙利命名法
匈牙利命名法是由微软公司的程序员Charles Simonyi提出的,主要应用于Windows编程。其核心思想是以变量的数据类型作为前缀,然后跟上变量的描述性名称。基本原则是:变量名 = 属性 + 类型 + 对象描述。
以链表为例,假设我们有一个存储整数值的单向链表,其中每个节点包含一个整数值和一个指向下一个节点的指针。我们可以按照以下方式命名:
- 链表节点的命名:可以将节点的数据类型作为前缀,然后跟上节点的描述性名称。例如,对于存储整数值的链表节点,可以命名为
IntNode
或iNode
。 - 链表的命名:对于整数值的单向链表,可以将链表的数据类型作为前缀,然后跟上链表的描述性名称。例如,可以命名为
IntLinkedList
或iLinkedList
。
以下是属性的具体缩写:
g_ 全局变量
c_ 常量
m_ C++类成员变量
s_ 静态变量
以下是前缀类型的具体缩写:
a 数组(Array)
b 布尔值(Boolean)
by 字节(Byte)
c 有符号字符(Char)
cb 无符号字符(Char Byte)
cr 颜色参考值(Color Ref)
cx, cy 坐标差(长度 Short Int)
dw 双字(Double Word)
fn 函数(Function)
h Handle(句柄)
i 整形(Int)
l 长整型(Long Int)
lp 长指针(Long Pointer)
m_ 类成员(Class Member)
n 短整型(Short Int)
np 近程指针(Near Pointer)
p 指针(Pointer)
s 字符串(String)
sz 以 Null 做结尾的字符串型(String with Zero End)
w 字(Word)
这种命名法在IDE不成熟的年代非常有用,因为它可以帮助开发者快速识别变量类型。虽然现在IDE已经能够提供类型提示,但匈牙利命名法在某些场景下仍然具有高效性。
驼峰命名法
驼峰命名法分为大驼峰式命名法和小驼峰式命名法。这种命名方式的特点是将单词的首字母大写,其他小写,组合在一起形成类似驼峰的结构。
大驼峰式命名法:每个单词的首字母都大写,单词之间没有下划线或其他分隔符。例如:
DataBaseUser StudentInformation
大驼峰命名法通常用于表示类名或接口名,因为类名通常是一种抽象概念,而大驼峰命名法的格式能够清晰地表示类名的含义。例如,
Person
、Car
、UserInfo
等都是使用大驼峰命名法命名的类名。小驼峰式命名法:除了第一个单词外其他单词首字母都大写,单词之间没有下划线或其他分隔符。例如:
myVariable getUserInfo calculateTotal
小驼峰命名法通常用于表示变量名、函数名等具体实体的命名,因为这些命名通常是与具体操作或属性相关联的。小驼峰命名法的格式能够清晰地表示变量或函数的含义,使代码易于理解和维护。
蛇形命名法/下划线命名法
这种命名方式多用于单词较多的时候,它的特点是各个单词之间使用下划线“_”连接,并且通常所有字母都使用小写。例如:
my_variable
get_user_info
calculate_total
当我们命名所需单词较多时,往往蛇形命名法更占优。例如:
void should_get_200_status_code_when_request_is_valid() // 蛇形
void shouldGet200StatusCodoWhenRequestIsValid() // 驼峰
很明显蛇形命名法的可读性更高。
串式命名法
这种命名方式和蛇形命名法很像,它的特点是各个单词之间使用连字符“-”连接,并且通常所有字母都使用小写。例如:
my-variable
get-user-info
calculate-total
结合使用
实际上,没有绝对的需要使用指定的哪种方法来命名,你完全可以创造你自己的命名方式,只要它足够方便足够可读,你也完全可以将以上的命名方式结合起来使用,来形成最适合自己的那种,而在团队合作中,也绝不会只使用简单的驼峰或者是蛇形,团队需要形成一定的属于自己的命名规范,这样才能做到团队成员高效合作。
可读性规则
以上介绍的是语法规范,但实际上我们在命名时不仅要注意语法上的规范,对于代码本身的可读性也需要注意,单词是否需要缩写,单词的排列顺序是怎样的,这些也值得我们探讨。
“编程本身就是一种社会活动,大部分的编程活动都是人与人协作的过程”。
在人类的社交活动中,明确才是第一目标。尽可能做到顾名思义才是代码命名存在的本身意义。所以,在代码的构造中,我们也应该遵循以下几点:
- 语义清晰:使用带有语义的命名,能够让维护代码的人更容易理解和修改代码。
- 名副其实:名称不需要注释补充就可见其含义、用途。
- 排斥不必要废话:不要写多余的废话或者容易让人混淆的命名。比如"customerObject"和"customer",这种就是意义混杂的废话。莫名其妙多出来的Object实际上并无意义。我们区分应该使用特定的可以区分的命名来描述它。
- 避免非公认缩写/简写——可读性>简短性:为了能让命名更加易懂和易读,尽量不要缩写/简写单词,除非这些单词已经被公认可以被这样缩写/简写。像链表,LinkList,你当然不能写成LLst等,晦涩难懂。
- 使用可读的名称:我们要规避过于罕见或者根本不常用的单词,甚至是自己创造的词语,那更是禁忌,毕竟代码是给人读的,而不是什么过于抽象的艺术作品。
- 类名和对象名应该是名词或名词短语。
- 方法名应当是动词或动词短语:如postPayment、deletePage或save。属性访问器、修改器和断言应该根据其值命名,并依Javabean标准加上get、set和is前缀。
- 每个系列词组中选一个词作为标志词,代表它属于这个组:在同类型的词中,就应该只有一个命名,例如链表,那么操作的命名中都应该带有LT(LinkList),例如:
LTPushFront LTInsert LTInit
- 专业化、术语化、精简化:我们应该尽量用术语(CS术语,算法,数学术语)命名;尽量用那些计算机科学(Computer Science,CS)术语、算法名、模式名、数学术语;尽量使用问题涉及领域的术语;避免使用非专业术语;避免使用中文,拼音;避免命名过长。
提高代码规范
在遵循以上规则和了解了基本的命名方法之后,我们可以通过以下方式或途径来提高自己的代码规范,养成一定的好习惯之后,那么优秀的命名必定会不请自来。
- 不断试错,不断润色:把你的变量名问别人,无论是懂代码还是不懂,他说的和你想的大致不差,就照着这个方向去修改,去润色。直到别人能很清晰地读懂你的命名——毕竟命名的第一要事就是可读性。
- 学习企业/大型项目命名:看别的大型项目源码是怎么起名的,哪些变量名使用的频率最高,或者关注大厂的命名有哪些值得学习的地方,站在巨人的肩膀上,往往能看得更远。
- 参考命名网站:例如Codelf、CHTML等等命名网站,参考它们的好处是通常它们集合了大部分大众适用,使用率高的命名方式,那么也就可以保证命名的容错率,从而了解大致的命名方向和命名规则。
后序
“如果讨论一下就知道,如果名称改得更好,那大家真的会感激你。多数时候我们并不记忆类名和方法名。我们使用现代工具对付这些细节,好让自已集中精力于把代码写得就像词句篇章、至少像是表和数据结构(词句并非总是呈现数据的最佳手段)。改名可能会让某人吃惊,就像你做到其他代码改善工作一样。别让这种事阻碍你的前进步伐。”
代码的命名规范不过是Clean Code之中的一环,当我们锻炼好了我们作为一个程序员的思想维度和代码感,那么对于好的命名也就信手拈来了,毕竟,最终的结果取决于你自己。