代码洁癖系列(二):命名的艺术

不知道大家还记不记得《家有儿女》里有这么一段经典台词:“我叫夏雪”,“我叫夏雨”,“我叫夏冰雹”。

xiabingbao

刘星自己给自己起的名字承包了我所有笑点。但仔细想想这名字取的竟然还挺不错,不但有意义,还和夏雨夏雪的名字相呼应。

回到主题,在我们的代码里,命名是随处可见的,比如给包命名,给类命名,方法名,参数名,变量名等等。那么什么样的命名才算是好的命名呢。这就是我们今天要讨论的。

名副其实

首先还是要强调这一点,我读过的糟糕的代码有一个共同的特点,那就是代码中存在大量随意的,无意义的命名。比如:表示消耗多少小时的变量命名为h,同作用域中还有一个想要表示“小时”相关的变量直接命名为h1,一个List类型的变量就命名为list。读这种代码不会令人开心,同时写这种代码的程序员的人身安全是无法保证的。

1
2
3
4
5
6
7
8
9
public List<String> getThem() {
List<String> list = new ArrayList<>();
for (String key : keys) {
if (theMap.get(key) == 1) {
list.add(key);
}
}
return list;
}

读一下上面这段代码,能看出有什么问题吗?或者说看完有人明白这段代码要做什么吗?

我先来说一下我的问题:

  1. getThem是get什么?
  2. list里存的是什么
  3. keys指的是什么,为什么遍历它
  4. 常量”1“的意义是什么

这几个问题可能只有写这段代码的人才能解释(没错,就是我写的)。所以我来给大家解释一下,不过我不想一一回答上面的问题,我把代码重写一遍,看看还会不会有这样的问题。

1
2
3
4
5
6
7
8
9
public List<String> getPaidOrderIds() {
List<String> paidOrderIds = new ArrayList<>();
for (String orderId : orderIds) {
if (orderStatus.get(orderId) == OrderConstatn.PAID) {
paidOrderIds.add(orderId);
}
}
return paidOrderIds;
}

怎么样,上面的问题都清楚了吗,如果不清楚可以私下和我联系,我会给你推荐一个非常好的英语学习软件。

这就是名副其实的重要性。

避免误导

命名过程中要注意的第二点就是要避免名称对别人产生误导,例如上面代码中paidOrderIds这个变量,如果我们命名成paidOrderIdList呢,看起来似乎没什么问题,但是如果这个变量是Set类型或者其他类型呢?命名为xxxList还合适吗,别人读代码的时候会下意识的认为这是个List类型的变量(尽量避免名称中出现类型的名字)。

另一点容易产生误导的是数字和字母相像的情况,比如,我命名一个变量叫做O1,在编辑器里就很难分辨是O1还是01,如果我写一个这样的表达式

1
O0 = l1;

估计别人会以为我发明了什么新的语言吧。

第三点是要避免区别较小的两个名称,比如XYZContinentController和XYZCentinentController这样的命名,对于读代码的人来说简直就是灾难,对于写代码的人来说也存在很大的风险。(为什么不是灾难?因为大部分人都是Ctrl+C/Ctrl+V的,这样就减小一些出错的几率。看来善用Ctrl+C/Ctrl+V还是很有必要的)

做有意义的区分

编译器要求我们在同一个区域内不能重复命名。那么有的程序员就会写出a1,a2,a3……这样的命名,这看起来很烂,谁也不知道它们有什么区别。再举过来一个栗子,一个包中有两个类,Product和ProductInfo,这时让你查一下商品名称,你知道要去哪个类里找吗?事实证明,这样的命名与a1,a2,a3之流别无二致。

既然要做区分,为什么不做些有意义的区分呢,一个类叫做Product,表示商品信息,另一个叫做ProductStocks表示商品的库存信息。这样是不是更清晰一点呢,当然,我这里只是举个栗子,实际上可能不需要这样定义。

别随意使用简写

不要随意使用简写,除非是大家都知道的简写。比如美国的命名写成US,大家都可以理解,而如果generateCode写成genCode就令人费解了。

使用可以被搜索的名称

像我们在一开始的那段代码,为什么要把常量“1”写成OrderConstatn.PAID,不仅是为了可读,也是为了可搜索,试想,如果你要找这段代码,去搜索数字1,会有多少结果?搜索PAID呢?亲自试过之后相信你会回来点赞的。

类名和方法名

类名和方法名也要遵循上面的规范,除此之外,它们还有各自的规范:

  • 类名不应该是动词,避免使用Data、Info这样的词汇。
  • 方法名应该是动词,比如,saveXXX、deleteXXX

要专一

假如你在不同的类中,分别定义了方法getXXX、fetchXXX和findXXX,我要调用的时候怎么知道某个类中应该使用哪种方法?所以,为什么不都用getXXX的形式呢?这样无论是对写代码的人还是对调用的人来说都是莫大的喜讯。

适当添加语境

当你一些变量:firstName、lastName、street、houseNumber、city、state、zipcode。我们可以很轻易的判断出,他们组合在一起表示一个地址。那么把state单独拿出来呢?你还能知道它是什么意思吗?这时,我们可以把变量命名为addrState、addrFirstName……这样即便单独看某个变量,也会理解它要表达什么。当然更好的方法是定义一个名为Address的类,把这些变量放到类中,事实上我们也都是这样做的。

当然,有时候也不能添加一些无意义的语境。我们要开发一个“画图”的应用,那在每个类名前加Drawing可不是什么好主意。

结语

命名并不能算是什么技术,而是一种写代码的习惯,但这种习惯有可能会决定你作为一名程序员给人的第一印象。所以,养成一个好的命名习惯,也是对自己形象的维护。同时还能让自己的生命安全更有保障(避免被同事……

Jackey Wang wechat
欢迎关注我的公众号,一起讨论如何写bug
-------------本文结束感谢您的阅读-------------
原创不易,感谢支持