编写可读代码的艺术读书笔记--把信息装到名字里

论坛 期权论坛 脚本     
已经匿名di用户   2022-7-2 22:16   3830   0

选择专业的词。

例如,“get”这个词就非常不专业,例如在下面的例子中:

def GetPage(url)

“get”这个词没有表达出很多信息。这个方法是从本地的缓存中得到一个页面,还是从数据库中,或者从互联网中?如果是从互联网中,更专业的名字可以是FetchPage()或者DownloadPage()。

单词 更多选择

send deliver、dispatch、announce、distribute、route

find search、extract、locate、recover

start launch、create、begin、open

make create、set up、build、generate、compose、add、new


避免泛泛的名字(或者说要知道什么时候使用它)。

像i、j、i t e r和i t等名字常用做索引和循环迭代器。尽管这些名字很空泛,但是大家都知道它们的意思是“我是一个迭代器”。但有时会有比i、j、k更贴切的迭代器命名。例如,下面的循环要找到哪个u s e r属于哪个club:

for (int i = 0; i < clubs.size(); i++)

    for (int j = 0; j <clubs[i].members.size(); j++)

        for (int k = 0; k < users.size(); k++)

            if (clubs[i].members[k] == users[j])

                 cout << "user[" << j << "] is in club[" << i <<"]" << endl;

在if条件语句中,members[]和users[]用了错误的索引。这样的缺陷很难发现,因为这一行代码单独来看似乎没什么问题:

if (clubs[i].members[k] == users[j])

在这种情况下,使用更精确的名字可能会有帮助。如果不把循环索引命名为(i、j、k),另一个选择可以是(c l u b_i、m e m b e r s_i、u s e r_i)或者,更简化一点(c i、m i、ui)。这种方式会帮助把代码中的缺陷变得更明显:

if (clubs[ci].members[ui] == users[mi]) #缺陷!第一个字母不匹配。

如果用得正确,索引的第一个字母应该与数据的第一个字符匹配:

if(clubs[ci].members[mi] == users[ui]) #OK。首字母匹配。


用具体的名字代替抽象的名字。

例如,假设你有一个内部方法叫做ServerCanStart(),它检测服务是否可以监听某个给定的TCP/IP端口。然而ServerCanStart()有点抽象。CanListenOnPort()就更具体一些。这个名字直接地描述了这个方法要做什么事情。


使用前缀或后缀来给名字附带更多信息。

例如,这里有些JavaScript代码用来度量一个网页的加载时间:

var start = (new Date()).getTime(); //top of the page

var elapsed = (newDate()).getTime() - start; // bottom of the page

document.writeln("Load time was: " + elapsed + " seconds");

这段代码里没有明显的错误,但它不能正常运行,因为getTime()会返回毫秒而非秒。

通过给变量结尾追加_ms,我们可以让所有的地方更明确:

var start_ms = (newDate()).getTime(); // top of the page

...

var elapsed_ms = (newDate()).getTime() - start_ms; //bottom of the page

document.writeln("Loadtime was: " + elapsed_ms / 1000 +" seconds");


决定名字的长度。

程序员有时会采用首字母缩略词和缩写来命令,以便保持较短的名字,例如,把一个类命名为BEManager而不是BackEndManager。这种名字会让人费解。有时名字中的某些单词可以拿掉而不会损失任何信息。例如,ConvertToString()就不如ToString()这个更短的名字,而且没有丢失任何有用的信息。同样,不用DoServeLoop(),ServeLoop()也一样清楚。


利用名字的格式来表达含义

对于下划线、连字符和大小写的使用方式也可以把更多信息装到名字中。例如,下面是一些遵循Google开源项目格式规范的C++代码:

static const int kMaxOpenFiles= 100;

class LogReader {

  public:

         void OpenFile(string local_file);

  private:

         int offset_;

         DISALLOW_COPY_AND_ASSIGN(LogReader);

};

对不同的实体使用不同的格式就像语法高亮显示的形式一样,能帮你更容易地阅读代码。

该例子中的大部分格式都很常见,使用CamelCase来表示类名,使用lower_separated来表示变量名。但有些规范也可能会出乎你的意料。 例如,常量的格式是k C o n st a n t N a m e而不是C O N S T A N T_N A M E。这种形式的好处是容易和#define的宏区分开,宏的规范是MACRO_NAME。类成员变量和普通变量一样,但必须以一条下划线结尾,如o f f s et_。刚开始看,可能会觉得这个规范有点怪,但是能立刻区分出是成员变量还是其他变量,这一点还是很方便的。例如,如果你在浏览一个大的方法中的代码,看到这样一行:

stats.clear();

你本来可能要想“stats属于这个类吗?这行代码是否会改变这个类的内部状态?”如果用了member_这个规范,你就能迅速得到结论:“不,stats一定是个局部变量。否则它就会命名为stats_。”


不会误解的名字

当要定义一个值的上限或下限时,max_和min_是很好的前缀。对于包含的范围,first和last是好的选择。对于包含/排除范围,begin和end是最好的选择,因为它们最常用。

布尔值命名:通常来讲,加上像is、has、can或should这样的词,可以把布尔值变得更明确。例如,S p a c e L e f t()函数听上去像是会返回一个数字,如果它的本意是返回一个布尔值,可能HasSapceLeft()个这名字更好一些。

要小心用户对特定词的期望。例如,用户会期望get()或者size()是轻量的方法。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP