湾区日报上分享的一篇文章,文章的作者在Google设计Dart语言,就变量命名方面给了4点建议,文中也列出了好变量名、坏变量名的对比。不管作者的看法与你实际中的命名习惯是否一致,看完这篇文章,相信可以在变量命名方面有一些新的思考。

  英文原文:Long Names Are Long

  译/Giraffe

  Google做的最明智的规定之一就是严格执行code review。每一个改动在上线之前,都要经过两种形式的review。首先,团队中的人会进行常规的review,以确保代码完成了它应该完成的功能。

  接下来还会进行可读性层面的review。顾名思义,它是为了确保代码是可读性高的:是否利于理解和维护?是否符合该编程语言的一些惯例?是否有良好的文档?

  Dart已经开始Google内部使用,所以我有幸参与了n次上面类型的code review。作为该语言的设计者,这是一项令人着迷的工作。我可以直接看到人们是如何使用Dart的,这对语言的进一步发展很有帮助。在reivew的同时,我也能够清晰的了解到那些比较常见的错误和使用最多的特性,我就好像是一个记录本地居民生活的人类学者。

  当然,上面说的与本文的主旨无关,这并不是一篇关于Dart的文章。本文主要是想讨论我看到过的一些令人抓狂的代码:这些代码的变量命名实在是太尼玛的长了。。。

  是的,变量的名称可以很短。回到当C语言中外部标识符仅需要由前六个字符来唯一的区分;自动补全功能还没有发明;每次按键盘都像在雪地上坡一样艰难的时候,长的命名就会带来很多问题。不过幸运的是,我们现在生活的世界太美好了,键盘操作变得如此简单。

  但我们现在似乎走上了另一个极端,我们不应该做海明威,但我们也无需成为田纳西·威廉斯。代码中使用了超长的命名会影响代码的清晰性。同时,超长的变量命名会造成换行,这会影响代码的结构,不易于阅读。

  • 长的类名会使开发者不易声明该类型的变量。
  • 长的方法命名会使它变得晦涩难懂.
  • 长的变量命名不利于代码重用,导致过长的方法链。

  我曾见过超过60个字符的变量命名,你甚至可以写首诗。别慌,下面我们来看看如何解决这一问题。

  选择一个好的命名

  命名有两个目标:

  • 清晰:你要知道该命名与什么有关
  • 精确:你要知道该命名与什么无关

  当一个命名完成上面两个目标之后,其余的字符就是多余的了。下面是我在开发时的一些命名原则:

  命名中无需含有表示变量或参数类型的单词

  如果使用如Java之类的静态类型语言,开发者通常知道变量的类型。由于方法的实现一般都比较简短,所以即便是在查看一个需要推断才知道类型的本地变量,或者在code review等静态分析器不可用的情况下,我们也可以通过多看很少的几行代码就能知道变量的类型。

  所以将类型说明加入到变量名中是多余的。我们应该舍弃匈牙利命名法,如下:

// 不好的:
String nameString;
DockableModelessWindow dockableModelessWindow; // 改进:
String name;
DockableModelessWindow window;

  特别是对于集合来说,最好使用名词的复数形式来描述其内容,而不是使用名词的单数形式来描述。如果开发者更在乎集合中存储的内容, 那么变量命名应当反映这一点。

// 不好的:
List<DateTime> holidayDateList;
Map<Employee, Role> employeeRoleHashMap; // 改进:
List<DateTime> holidays;
Map<Employee, Role> employeeRoles;

  这一点也同样适用于方法的命名。方法名不需要描述它的参数及参数的类型——参数列表已经说明了这些。

// 不好的:
mergeTableCells(List<TableCell> cells)
sortEventsUsingComparator(List<Event> events,
Comparator<Event> comparator) // 改进:
merge(List<TableCell> cells)
sort(List<Event> events, Comparator<Event> comparator)

  省略命名中不是用来消除歧义的单词

  有些开发者倾向于将他们知道的有关这个变量的所有信息都塞到命名里。要记住,命名只是一个标识符:只是告诉你该变量是在哪定义的。并不是用来告诉阅读者所有他们想知道的有关这个对象的详细信息。这是定义应该做的事情的。 命名只是让你找到它的定义。

  当我看到一个叫recentlyUpdatedAnnualSalesBid(最近更新的全年销售投标)的标识符时,我会问:

  • 存在不是最近更新的全年销售投标么?
  • 存在没有被更新的最近的全年销售投标么?
  • 存在最近更新的非全年的销售投标么?
  • 存在最近更新的全年非销售的投标么?
  • 存在最近更新的全年销售非投标的东东吗?

  上面任何一个问题的回答是“不存在”,就意味着命名中引入了无用的单词。

// 不好的:
finalBattleMostDangerousBossMonster;
weaklingFirstEncounterMonster; // 改进:
boss;
firstMonster;

  当然,你可能会觉得这有一些过了。比如将第一个例子的标识符简化为bid,会让人觉得有点模糊不清。但你可以放心大胆的这样做,如果在之后的开发中觉得该命名会造成冲突或不明确,可以添加些修饰词来完善它。反之,如果一开始就取了一个很长的命名,你是不可能在之后重新回来简化它的。

  省略命名中可以从上下文获取的单词

  我可以在文章中使用”我”,因为读者都知道这是一篇由Bob Nystrom所做的博客。我蠢萌的脸就挂在那,我无需不停的说我的名字。写代码也是一样,类中的方法/属性和方法中的变量,都是存在在上下文中的,无需重复。

// Bad:
class AnnualHolidaySale {
int _annualSaleRebate;
void promoteHolidaySale() { ... }
} // Better:
class AnnualHolidaySale {
int _rebate;
void promote() { ... }
}

  实际上,一个命名嵌套的层次越多, 它就有更多的相关的上下文,也就更简短。换句话说,一个变量的作用域越小,命名就越短。

  省略命名中无任何含义的单词

  我常常在许多游戏开发中看到包含无任何含义的单词的命名,一些开发者喜欢在命名中添加一些看起来有点严肃的单词。我猜可能他们觉得这样做可以让他们的代码显得重要,或者说让他们觉得自己更重要。

  实际上,有一些词语并没有实际意义,只是一些套话。比如:data, state, amount, value, manager, engine, object, entity和instance。

  一个好的命名能够在阅读者的脑海中描画出一幅图画。而将某变量命名为”manager”并不能向读者传达任何有关该变量是做什么的信息。它是用来做绩效评估的吗? 它是管理加薪的吗?

  在命名时可以问一下自己,把这个单词去掉含义是不是不变?如果是,那就果断把它剔除吧~~

  实际例子——华夫饼

  为了让大家了解以上的命名原则在实际中如何应用,这有个违法了以上所有原则的反例。这个例子和我实际上review过的一段代码一样令人心碎。。。。

// 好吃的比利时华夫饼
class DeliciousBelgianWaffleObject {
void garnishDeliciousBelgianWaffleWithStrawberryList(
List<Strawberry> strawberryList) { ... }
}

  首先,通过参数列表我们可以知道方法是用来处理一个strawberry的列表,所以可以在方法命名中去掉:

class DeliciousBelgianWaffleObject {
void garnishDeliciousBelgianWaffle(
List<Strawberry> strawberries) { ... }
}

  除非程序中还包含不好吃的比利时华夫饼或者其他国家的华夫饼,不然我们可以将这些无用的形容词去掉:

class WaffleObject {
void garnishWaffle(List<Strawberry> strawberries) { ... }
}

  方法是包含在WaffleObject类中的,所以方法名中无需Waffle的说明:

class WaffleObject {
void garnish(List<Strawberry> strawberries) { ... }
}

  很明显它是一个对象,任何事物都是一个对象,这也就是传说中的“面向对象”的含义,所以命名中无需带有Object

class Waffle {
void garnish(List<Strawberry> strawberries) { ... }
}

  好了,这样看起来好多了。

  以上就是我总结的相当简洁的命名原则。可能有些人会觉得无需在命名上耗费太多的精力,但我认为命名是开发过程中最基本的任务之一。

  ————————————————–我是萌萌哒分界线————————————————

  感觉变量或者方法的命名,看似简单,实际很难,特别是想一个简洁明了、可读性高的命名。自己也经常用什么dataxxxlist来命名,作者说的挺对的,前者没什么意义,后者又有点啰嗦。不过对于集合类型的变量,统一用名词复数命名容易混淆。举个例子对于Apple这个类来说,可能存在List和Map两种集合类型的变量。个人觉得对List类型的变量可以采用名词复数来命名,Map类型的变量可以采用valueByKey格式来命名,比较容易区分。

http://kb.cnblogs.com/page/548394/

如何给变量取个简短且无歧义的名字(转) good的更多相关文章

  1. MariaDB MySQL变量取值避免四舍五入的方法

    MySQL变量取值避免四舍五入的方法 By:授客 QQ:1033553122 在一些对数据精确度要求比较高的场景(比如资金结算)下,变量取值时不能对变量值进行四舍五入操作,这时候就要做些预处理工作. ...

  2. unwrapped与wrapped变量取值的问题

    unwrapped与wrapped变量取值的问题 当我们在定义一个tableView时,是可以使用3种定义方式的,第一种就是定义成optional(AnyObject?)形式,第二种为non-opti ...

  3. python测试开发django-67.templates模板变量取值

    前言 django 的模板里面变量取值是通过句点语法来取值,就是一个点(.)符号.取值的对象也可以是字符串,int类型,list列表,字典键值对,也可以是一个类的实例对象. views视图 比如我在 ...

  4. JS规则 给变量取个名字(变量命名) 必须以字母、下划线或美元符号开头;区分大小写;不允许使用JS关键字或保留字

    给变量取个名字(变量命名) 我们为了区分盒子,可以用BOX1,BOX2等名称代表不同盒子,BOX1就是盒子的名字(也就是变量的名字). 我们赶快给变量取个好名字吧!变量名字可以任意取,只不过取名字要遵 ...

  5. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...

  6. python通过函数改变变量取值

    严格讲应该是"通过函数调用,改变引用对象".python中,要区分"变量名"和"对象" 如果是类的对象,是引用类型的,那么可以通过函数调用, ...

  7. javascript 变量声明有var与无var 的区别

    1.在函数作用域内 加var定义的变量是局部变量,不加var定义的就成了全局变量.使用var定义var a = 'hello World';function bb(){var a = 'hello B ...

  8. golang for 循环变量取内存地址

    前几天提交的代码进行测试的时候发现变量无法赋值,原始代码如下: for _, asset := range dspInfo.native.Assets { var resAsset protocol. ...

  9. es6 解构写法:给变量取别名

    在变量后面加一个: var {f: foo} = {f: 5}; foo == 5 // true

随机推荐

  1. jquery新增,删除 ,修改,清空select中的option

    jQuery获取Select选择的Text和Value: 1. var checkText=jQuery("#select_id").find("option:selec ...

  2. PHP删除HTMl标签

    /** * 取出html标签 * * @access public * @param string str * @return string * */ function deletehtml($str ...

  3. poj2987 Firing

    以前只是A过很简单的最大闭合权像hdu1565之类,完全的最大流模板题.但是都完全不太懂最大闭合权的定义及其用途. 关于最大流的基础知识,大家可以自己网上搜索关键字.有点基础的哥们妹们,推荐看看胡伯涛 ...

  4. Hive入门之UDFS函数

    一.UDFS函数介绍 1. 基本UDF (1)SHOWFUNCTIONS:这个用来熟悉未知函数. DESCRIBE FUNCTION<function_name>; (2)A IS NUL ...

  5. 利用merge存储引擎来实现分表

    我觉得这种方法比较适合,那些没有事先考虑,而已经出现了得,数据查询慢的情况.这个时候如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码,因为程序里面的sql语句已经写好了,现在一张表要分成几十 ...

  6. $()和getElementById()的区别

    jQuery的成功多归功于其强大的选择器. 然而,相信不少初学jQuery的同学都会遇到下面的问题. 在javascript下,我们可以根据getElementById()来获取页面元素.如下: va ...

  7. 本地环境下 WordPress 环境搭建与安装

    本地环境:Ubuntu 14.04 使用软件: WordPress 4.1.1 中文优化版 EasyEngine 安装步骤: 安装 LNMP 环境; wget -qO ee rt.cx/ee & ...

  8. linux之sed

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为:         sed ...

  9. css em

    em与px换算 任意浏览器的默认字体高度16px(16像素).所有未经调整的浏览器都符合: 1em=16px.那么,12px=0.75em,10px=0.625em.为了简化font-size的换算, ...

  10. 关于mysqli 连接数不能正确释放的解决方案

    /** * 析构函数 */ //解决重复链接的问题 private $db_handler = null; function __destruct() { Log::logWrite($this-&g ...