好命名胜于任何注释

来源:互联网 发布:mac版本pscs6破解文件 编辑:程序博客网 时间:2024/04/28 02:58


     设计软件除了从思想上要把握其结构,在实现上也得费番心思,比如变量与函数的命名就位列其中,毕竟程序是设计思想的物质外壳,再好的思想必须通过最后的程序代码去体现。命名的重要性如同写文章时的用词和语句的组织,一篇好的文章除了注意用词,还得将文章组织得“行云流水”,为程序命名也如此。

    现在通过一个例子来说明命名的重要性,假设要为双向链表(Double-Linked List,简称dll)设计一个函数,这个函数的功能是从链表中删除其头节点并将这一节点当作函数的返回值返回,那如何给这一函数取名呢?dll_get_head()这个命令可能会浮现在读者的脑海之中,但是这个命名并不好,因为get所表达的只是取,而没有删除的意思。也就是说,当程序员读到对于dll_get_head()函数的调用时,有可能理解为“只是引用头节点,且这一节点仍将保留在链表中”,这显然没有精确地传达设计本意。那dll_extract_head()呢?也同样不好,extract也不能表达从链表中删除节点的意思。如果用过WinZip的英文版就会发现,其中解压文件就用了extract这一词。更好的命名是dll_pop_head()!pop这一词来源于栈操作,压栈和退栈使用的英文分别是push和pop,当从栈中pop一个元素时,其意味着这一元素将从栈中被删除。除了函数名的命名很重要,函数参数同样重要,因为参数能取到点睛的作用。对于图1中的两个函数,从函数名和参数来看就能完全明白其作用和如何使用,任何解释这两个函数功能和用法的注释都将显得有点多余。

os/source/common/inc/dll.h
void dll_insert_before (dll_t *_p_dll, dll_node_t *_p_ref, dll_node_t *_p_inserted);
void dll_insert_after (dll_t *_p_dll, dll_node_t *_p_ref, dll_node_t *_p_inserted);
图1
    在很多资料中都强调写注释对于一个好程序的重要性,甚至提出一个程序的源码其三分之一的篇幅应当是注释。对于“三分之一”这一提法笔者表示很不赞同,原因如下:
    1)程序员在读程序时第一反应是读代码而不是注释,如果代码能清楚地表达意思,那么就不存在需要写注释的必要性,如果写了那一定也是多余的。对于一个项目,如果注释占了整个源程序的三分之一,笔者怀疑其中很多都是废话,可能这么多注释的出现就只是为了做到“占三分之一”。
    2)注释与代码很容易在维护的过程中失步,因此会出现注释所表达的声音与源代码的真实实现完全不同。其带来的后果就是,程序员一旦发现代码与注释不同步,进而就会怀疑注释的真实性,于是干脆不理会注释,而是完全通过代码去理解本意。
    3)如果一个程序真的需要大量的注释,那很有可能是因为程序的命名并不直观。比如前面所举的dll_pop_head()的例子,是光采用这个名字不加任何注释好呢?还是用dll_get_head()这个名字,然后在其边上加上“这个函数将删除链表头并将其作为返回值返回”这一注释好?相信读者有自己的判断!

    请注意,千万不要将这一原则理解成“少注释是好程序的充分条件”,而应当理解为“少注释是好程序的必要条件”。这一原则想表达的是,“重视命名将导致注释多余进而减少,而不是注释少了后命名就好了”,显然因果不能颠倒。那是不是要一味的抵触注释呢?不是,必要的注释还是需要的。毕竟存在使用函数命名也无法清楚表达的情形,比如模块的整体设计思想如果通过函数去表达的话需要程序员对所有的函数都很熟悉才能领会。如果在模块的开始处写一些注释,就能起到挈领提纲的作用。大部分情形下(注意:只是大部分情形,并不是绝对)通过命名就能清楚地表达局部思想,而注释应当放眼于全局去写。

    从这一原则也可以得出另一个软件设计文档编写时的准则,即“写设计文档不在于页数的多少,而在于将问题说清道白”,不是吗?一页纸能写完的如果用了两页纸,那就会造成阅读这一文档的每一个读者都多浪费时间。由此看来,函数命名也好,写设计文档也好,如果作者不好好的推敲,那就是将他所节约下来的时间花到了每一个读者身上,哪一种方式更经济呢?


转自:http://yunli.blog.51cto.com/831344/274533


原创粉丝点击