代码整洁之有意义的命名!
代码整洁之有意义的命名!
月伴飞鱼名副其实
一个好的变量、函数或类的名称应该已经几乎答复了所有的大问题
它应该告诉你,这个名称所代表的内容,为什么会存在,做了什么事情,应该如何用等
如果一个名称需要注释来补充才能让大家明白其真正含义,那其实就不算是名副其实
举个栗子:
以下的这句代码里的d就不算是个好命名
- 名称d什么都没说,它没引起我们对时间消逝的感觉,更别说单位是天了
1 | int d; // elapsed time in days||经过了几天时间 |
避免造成误导
我们应该避免留下隐藏代码本意的错误线索,也应该避免使用与本意相悖的词
例如,别用accountList来指一组账号
- 除非它真的是List类型,用accountGroup、bunchOfAccounts,或者直接用accounts,都是更好的选择
尽量提防长得太像的名称:
想区分
XYZControllerForEfficientHandlingOfStrings
和XYZControllerForEfficientStorageOfStrings
- 会花费我们太多的时间
因为这两个词,实在太相似了
以同样的方式拼写出同样的概念才是信息,拼写前后不一致就是误导
尽量做有意义的区分
尽量避免使用数字系列命名
(a1、a2…….aN)
:
- 这样的名称纯属误导,因为很多时候完全没有提供正确的信息,没有提供导向作者意图的线索
废话是另一种没有意义的区分:
- 如果我们有一个Product类,还有一个ProductInfo或ProductData类,那么他们的名称虽然不同,但意思却无区别
- 这里的Info、Data就像a、an和the一样,是意义含混的废话
注意,只要体现出有意义的区分,使用a、the这样的前缀就没错
- 例如,将a用在域内变量,把the用于函数参数
尽量使用读得出来的名称
我们要使用读得出来的名称
如果名称读不出来,讨论的时候就会不方便且很尴尬,甚至让旁人觉得很蠢
- 例如,变量名称是
beeceearrthreecee
,讨论的时候读起来简直像没吃药
尽量使用可搜索的名称
单字母和数字常量有个问题,就是很难再一大篇文字中找出来
- 找
MAX_CLASSED_PER_STUDENT
很容易,但想找数字7,就很麻烦同样,字母e也不是个便于搜索的好变量名。因为作为英文中最常用的字母,在每个程序、每段代码中都有可能出现
名称长短应与其作用域大小相对应,若变量或常量可能在代码中多处使用,应赋予其以便于搜索的名称
举个栗子,比较如下两段代码:
1 | for (int j=0; j<34; j++) |
按整洁代码的要求来评判,第一段代码会让读者不知所云,第二段代码比第一段好太多
- 第二段代码中,sum并非特别有用的名称,但至少他搜索得到
采用能表达意图的名称,貌似拉长了函数代码,但要想想看,
WORK_DAYS_PER_WEEK
要比数字5好找得多
- 而列表中也只剩下了体现我们意图的名称
取名不要绕弯子
我们取名的时候要避免思维映射,不应当让读者在脑中把你的名称翻译为他们熟知的名称
- 也就是说取名不要绕弯子,而是要直白,直截了当
在多数情况下,单字母不是个好的命名选择,除非是在作用域小、没有名称冲突的地方,比如循环
- 循环计数器自然有可能被命名为i,j或k(最好别用字母l),这是因为传统上我们惯用单字母名称做循环计数器
程序员通常都是聪明人,聪明人有时会借助脑筋急转弯炫耀其聪明
而聪明程序员和专业程序员之间的区别在于,专业程序员了解,明确就是王道
专业的程序员善用其能,能编写出其他人能理解的代码
类名尽量用名词
类名尽量用名词或名词短语,比如Customer,WikiPage,Account 或 AddressParser
类名最好不要是动词
方法名尽量用动词
方法名尽量用动词或动词短语
- 比如
postPayment,deletePage
或者save属性访问器、修改器和断言应该根据其value来命名,并根据标准加上get、set和is前缀
举个栗子,这里的getName、setName等命名都很OK
1 | string name = employee.getName(); |
而重载构造器时,使用描述了参数的静态工厂方法名
1 | Complex fulcrumPoint =Complex.FromRealNumber(666.0); |
通常好于:
1 | Complex fulcrumPoint = new Complex(666.0); |
我们也可以考虑将相应的构造器设置为
private
,强制使用这种命名手段
每个概念对应一词,并一以贯之
我们需给每个概念选一个词,并且一以贯之
- 例如,使用
fetch、retrieve
和get来给在多个类中的同种方法命名,你怎么记得住哪个类中是哪个方法呢?同样,在同一堆代码中混用
controller、manager,driver
,就会令人困惑DeviceManager和Protocol-Controller之间有何根本区别?
为什么不全用controller或者manager?他们都是Driver吗?
- 这就会让读者以为这两个对象是不同的类型,也分属不同的类
所以,对于那些会用到你代码的程序员,一以贯之的命名法简直就是天降福音
通俗易懂
我们应尽力写出易于理解的变量名,把代码写得让别人能一目了然,而不必让人去非常费力地去揣摩其含义
我们想要那种大众化的作者尽责地写清楚的通俗易懂的畅销书风格
- 而不是那种学者学院风的晦涩论文写作风格
尽情使用解决方案领域专业术语
记住,只有程序员才会读你写的代码
- 所以,尽管去用那些计算机科学(Computer Science,CS)领域的专业术语、算法名、模式名、数学术语
对于熟悉访问者(Visitor)模式的程序来说,名称
AccountVisitor
富有意义给技术性的事物取个恰如其分的技术性名称,通常就是最靠谱的做法
添加有意义的语境
很少有名称是可以自我说明的
- 所以,我们需要用有良好命名的类,函数或名称空间来放置名称,给读者提供语境
若没能提供放置的地方,还可以给名称添加前缀
举个栗子,假如我们有名为
firstName、lastName、street、houseNumber、city、state
和zipcode的变量
当他们搁一块儿的时候,的确是构成了一个地址
不过,假如只是在某个方法中看到一个孤零零的state呢?
我们会推断这个变量是地址的一部分吗?
我们可以添加前缀addrFirstName、addrLastName、addrState等,以此提供语境
- 至少,读者可以知道这些变量是某个更大变量的一部分
当然,更好的方案是创建名为Address的类
这样,即便是编译器也会知道这些变量是隶属于某个更大的概念了
- 另外,只要短名称足够好,对含义的表达足够清除,就要比长名称更合适
添加有意义的语境甚好,别给名称添加不必要的语境
避免使用编码
使用编码 是一个不好的选择,把类型或者作用域添加的变量名中,无疑给变量名添加了额外的信息,增加了解码的负担
1 | string m_name; |
应该避免这样的命名方式,下面
python
语言为例:
1 | m_list; |