Clean Code第二章:有意义的命名 --阅读与讨论

尼克徐 发布于 2015年10月20日 | 更新于 2015年10月24日
清醒疯子 等1人欣赏。

本章,作为整洁代码的头一步,致力于规范命名规则。

alt text

图片来自Chapter 2. Meaningful Names

所谓名不正则言不顺,命名的好,代码可读性一下子就可以提高一大块。

本章讲解了十多种命名时的注意事项。

提到命名,使我想起谭浩强先生的书,我是从他的C语言编程书入门的。

虽说编程语言入门了,可那时养成了一些非常不好的编程习惯,给变量随便命名,就是其中一种。

随便摘一段该书中的代码:

long f1(int p)
{
    int k;
    long r;
    long f2(int);
    k=p*p;
    r=f2(k);
    return r;
}

除了仔细看代码外,基本看不出来该函数在干什么。

如果动辄几万行,几十万行的项目是这么命名,完全是惨不忍睹啊!

一, 命名要名副其实

如果命名还需要注释,那么该命名则是不合理的:

int d; // elapsed time in days

以下命名是合适的:

int elapsedTimeInDays; 
int daysSinceCreation; 
int daysSinceModification; 
int fileAgeInDays;

命名增加了可读性,例如如下代码,看起来就不知所云:

public List getThem() {
List list1 = new ArrayList(); 
    ......
    for (int[] x : theList)
        if (x[0] == 4) 
            list1.add(x);
    return list1; 
}

而如果是改成下面的两种,代码则清晰很多:

public List getFlaggedCells() {
    List flaggedCells = new ArrayList(); 
    ......
    for (int[] cell : gameBoard)
        if (cell[STATUS_VALUE] == FLAGGED) 
            flaggedCells.add(cell);
    return flaggedCells; 
}

或是

public List getFlaggedCells() {
    List flaggedCells = new ArrayList(); 
    ......
    for (Cell cell : gameBoard)
        if (cell.isFlagged()) 
            flaggedCells.add(cell);
    return flaggedCells; 
}

二, 避免误导

请避免使用与本意相混淆或相悖的词。

例如,aix,sco,hp,不该作为变量名,因它们都是UNIX平台上的专有名称。

除非是List类型,否则不要用类似accountList来命名一组账号,可以命名为accountGroup。

1和l,O和0很容易混淆,请注意使用。

三,有意义的区分

例如,ProductInfo和ProductData就没有意义上的区别,很容易混淆。

废话都是冗余的,例如Variable用于变量名中,Table用于表名中。

四,使用读得出来的名称

命名尽量别缩写,时间长了谁都看不懂了。

以下命名,对比一下,哪个更容易读明白:

class DtaRcrd102 {
    private Date genymdhms;
    private Date modymdhms;
    private final String pszqint = "102"; 
    /* ... */
};
class Customer {
    private Date generationTimestamp; 
    private Date modificationTimestamp;
    private final String recordId = "102"; 
    /* ... */
}

五,使用可搜索的名称

如果变量可能在代码中多处使用,则应赋以便于搜索的名称。变量作用域越大,越需要精心命名以便搜索。

例如,如果一星期5天的“5”经常被使用,则将其命名为WORKDAYSPER_WEEK要比“5”好搜索的多。

六,尽量避免使用编码和成员前缀等“旧时代”规则

例如,匈牙利标记法,成员前缀(m_dsc等等)。现在的编程里,这种前缀和标记法的命名方法越来越少见了。

例如,抽象工厂及其实现,

可以写成:IShapeFactgory和ShapeFactory,

也可以写成ShapeFactory及ShapeFactoryImp.

作者推荐后者的写法。

七,避免思维映射

尽量别用脑中熟悉的缩写,来取变量名。

例如,i在编程人员眼中,经常代表index.但最好用当时有意义的名称来替代i.

八,类名

类名应当是名词或名词短语,例如Customer,WikiPage,AddressParser。

请避免用太通用的Data,Info等词。

类名不应该是动词。

九,方法名

方法名应该是动词或动词短语,例如:postPayment,deletePage或者save.

如果是属性访问,则加上"get","set","is"等前缀。

十,别扮可爱(卖萌)

别用俗语来做名称。

例如whack()来表示kill()等。

十一,每个概念对应一个词

请给每个抽象概念选一个词,并一以贯之。

例如,如果fetch,retrieve,get并列出现在方法名里,你怎么知道用哪个?

Controller和Driver,Manager也是令人困惑的一组词。

十二,别用双关语

请避免同一术语用于不同概念。例如,add方法,如果用于collection时,则应该叫append或insert更贴切。

十三,使用计算机科学领域的名称还是问题域的名称

如果能用计算机科学领域的术语,则尽量使用。因只有程序员才会读你的代码。

例如,AccountVisitor,程序员一看就知道这是访问者模式。

如果不能用程序员所熟悉的术语,则采用所涉问题领域来的名称。

至少,看到该名称,能联想到去找该领域专家来询问所需知识。

十四,添加有意义的语境

看到一个state变量,可能不知道它是什么意思,但如果是addrState,很容易看出它是地址的一部分。

如果state是Address类的成员,含义就更清晰了。

十五,不要添加没意义的语境

例如,给每个类添加一个全局前缀,一般都没有意义。因为所有的类都有此前缀,则变成了没有区别。

问题:

1,你所写过,改过或看过的代码中,有哪些是命名很糟糕的,请举例。

2,有哪些是命名很不错的,也请举例。

3,此章中命名的规范里,哪些是你已经遵守了的规则,哪些是你忽略了的?

如何加入Root Cause读书会:请加我的微信brainstudio,我建立了一个群,方便通知各位写读后感及讨论。

Clean Code所有讨论章节链接

共4条回复
chaichai 回复于 2015年10月21日

想起来之前被坑过的事情, 有两个变量的命名是这样的viewHead and headView, 而且很多地方都调用了这两个不同的变量, 到最后, 结果就是我完全分不清到底是viewHead了还是 headView了, 最坑的是他俩放一起真容易看成一个, 而且看不出他们的实际意义!

总结一下何为好的命名:

1.名副其实. 变量、函数或类的名称应该已经答复了所有的大问题. 它该告诉你, 它为什么会存在, 它做什么事, 该怎么用. 如果名称需要注释来补充, 那就不算名副其实.

2.做有意义的区分. 比如有三个类Product & ProductInfo & ProductData, 你能区分出他们的意思吗!

3.避免误导. 比如上面举到的viewHead和headView的例子. 再来个长一点的感受一下 XYZControllerForEfficientHandlingOfStrings 和 XYZControllerForEfficientStorageOfStrings 你分明白了吗?

4.使用读的出来的名称. 这样你与同事沟通就不用说这个、那个了, 说半天也不知道是哪个.

对于命名, GoF的23种Design Pattern核心价值之一就是清晰的命名了23种常用模式,不信你可以试试看能不能想出更好地命名.

尼克徐 回复于 2015年10月22日

1楼 @chaichai

有道理。

清晰命名了23种常用模式,就可以减少沟通成本,比如类型为Factory,Facade,Adapter,Visitor一看就知道是哪种类型的。

wjxtc 回复于 2015年10月22日

我想很多程序员不愿意写这么长的名字,很大一部分原因是英语不大行啊。。。

cnsoft 回复于 2015年10月24日

3楼 @wjxtc 基本上可以通过不断强化来解决问题. 毕竟都是常见词汇 重复次数多了就记住了. 很多时候是想偷点懒,包括我自己 随意性太强 呵呵.

@尼克徐 老徐,我在想书其实是死的, 有疑惑问,有解惑者就太好了. 有些书会举一些错误的例子说明, 我想很多人还是想看看具体正确的东西, 于是就可以调整自己错误的部分, 但这些很具体的操作方式就很少有书本能提到 咱们可以去GitBook搞一个读书笔记什么的. 没准以后也变成另外一本书了. 哈哈.

@chaichai 总结的太好了. 受益匪浅.

命名这事 其实也是写给自己看的, 太随意了 过几天 过几个月再回来看代码 因为要加功能或者修bug之类的. 自己都忘记了是不是就很痛苦. 更别提别人接手你的代码了.

以前上学的时候觉得老师讲的东西脱离实践太理论化了, 当时觉得真会做程序的才厉害. 现在想法就有些变化了, 我觉得理论更难得更宝贵. 可以指导行动. 而不会是野蛮的原始生长状态. 比如 甚至不知道命名有规则一些更好 更能解决很多问题. 也不知道调试代码还能下断点Debug.. 这些书本上都有提到过,虽然当时看的很空洞. 但结合实践之后 就会发现可以印证每一句话. 不过我想很多人还是不知道该如何合理命名, 时间紧任务急是吧- 那就先来一个吧. 下面我也有个办法来解决这个不知如何命名。

我现在基本上是这样的,

类名 函数名 参数名 变量名 都要是有意义的名称. 比如 WPStore 是Windows Store IOSStore 是苹果商店. 诸如此类. SoreListener 负责处理回调事件的接口类. 就一个函数. onPayResult 处理收到处理结果. 如果英文不好.我给个解决办法,

  1. 第一个就查字典. 或者参考同好的命名方式. 时间久了也仍然可以看得明白. 不推荐中文拼音.太恶心了. 不过也有 Weixin Weibo 这种其实也算是专属词了. 英文也是这个. 我没记错的话, 日文就有很多是外来词, 就是英文的谐音什么的 也是为了方便交流。

  2. 第二个办法就是阅读代码. 现在有很多开源的代码, 质量都特别高. 通过阅读可以强化自己.

最后就是一句心里话, 与人方便 与己方便。

登录 或者 注册
相关帖子