如何给变量取个简短且无歧义的名字(转) good
湾区日报上分享的一篇文章,文章的作者在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) { ... }
}
好了,这样看起来好多了。
以上就是我总结的相当简洁的命名原则。可能有些人会觉得无需在命名上耗费太多的精力,但我认为命名是开发过程中最基本的任务之一。
————————————————–我是萌萌哒分界线————————————————
感觉变量或者方法的命名,看似简单,实际很难,特别是想一个简洁明了、可读性高的命名。自己也经常用什么data
, xxxlist
来命名,作者说的挺对的,前者没什么意义,后者又有点啰嗦。不过对于集合类型的变量,统一用名词复数命名容易混淆。举个例子对于Apple这个类来说,可能存在List和Map两种集合类型的变量。个人觉得对List类型的变量可以采用名词复数来命名,Map类型的变量可以采用valueByKey格式来命名,比较容易区分。
http://kb.cnblogs.com/page/548394/
如何给变量取个简短且无歧义的名字(转) good的更多相关文章
- MariaDB MySQL变量取值避免四舍五入的方法
MySQL变量取值避免四舍五入的方法 By:授客 QQ:1033553122 在一些对数据精确度要求比较高的场景(比如资金结算)下,变量取值时不能对变量值进行四舍五入操作,这时候就要做些预处理工作. ...
- unwrapped与wrapped变量取值的问题
unwrapped与wrapped变量取值的问题 当我们在定义一个tableView时,是可以使用3种定义方式的,第一种就是定义成optional(AnyObject?)形式,第二种为non-opti ...
- python测试开发django-67.templates模板变量取值
前言 django 的模板里面变量取值是通过句点语法来取值,就是一个点(.)符号.取值的对象也可以是字符串,int类型,list列表,字典键值对,也可以是一个类的实例对象. views视图 比如我在 ...
- JS规则 给变量取个名字(变量命名) 必须以字母、下划线或美元符号开头;区分大小写;不允许使用JS关键字或保留字
给变量取个名字(变量命名) 我们为了区分盒子,可以用BOX1,BOX2等名称代表不同盒子,BOX1就是盒子的名字(也就是变量的名字). 我们赶快给变量取个好名字吧!变量名字可以任意取,只不过取名字要遵 ...
- 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析
文章中引用的代码均来自https://github.com/vczh/tinymoe. 看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...
- python通过函数改变变量取值
严格讲应该是"通过函数调用,改变引用对象".python中,要区分"变量名"和"对象" 如果是类的对象,是引用类型的,那么可以通过函数调用, ...
- javascript 变量声明有var与无var 的区别
1.在函数作用域内 加var定义的变量是局部变量,不加var定义的就成了全局变量.使用var定义var a = 'hello World';function bb(){var a = 'hello B ...
- golang for 循环变量取内存地址
前几天提交的代码进行测试的时候发现变量无法赋值,原始代码如下: for _, asset := range dspInfo.native.Assets { var resAsset protocol. ...
- es6 解构写法:给变量取别名
在变量后面加一个: var {f: foo} = {f: 5}; foo == 5 // true
随机推荐
- ASP.NET MVC开发必看系列
一.关于HTTP协议的那些事 这可以说我们开发WEB程序的空气,推荐不断温故知新! HTTP协议 (一) HTTP协议详解 HTTP协议 (二) 基本认证 HTTP协议 (三) 压缩 HTTP协议 ( ...
- C# 颜色有3种表示方式: 6位16进制、RGB、 颜色关键字
最常用的是6位16进制的代码表示法.如bgcolor=#ff0000;其中#只是表示使用6位16进制的颜色代码声明颜色.代码的头两位即ff表示三原色中的红色,范围当然是16进制的00-ff,中间两位即 ...
- 浅谈Mybatis(二)
一.resultMap 作用:发现数据库的查询结果与实体之间不匹配时,需要通过ResultMap来进行映射处理.常用于多表查询. 多表查询还是比较复杂的,因为可能的情况很多.这里只说两种情况: 1.1 ...
- MySQL中的insert ignore into, replace into等的一些用法小结(转)
MySQL中的insert ignore into, replace into等的一些用法总结(转) 在MySQL中进行条件插入数据时,可能会用到以下语句,现小结一下.我们先建一个简单的表来作为测试: ...
- C# WINFORM 线程中更新UI
幸好今天是周末,有时间把这个问题记录一下.在多种语言之间切换,发现开发效率降的很低了,开发成本都集中到调式上了,C/C++这些放弃很久了,突然感觉线程这个问题搞的有点烦躁 我这里提到的线程中更新UI, ...
- Linux系统学习笔记之 1 基础命令
翻看日记,看到以前自己学习Linux是的笔记来了,温故而知新乎. 文件命名规则: 1.除了/之外,所有的字符都合法. 2.有些字符最好不要用,如空格符.制表符.退格符.和@ # & ( ) ...
- vc6.0批量编译
一直想研究一下怎么让电脑批处理编译程序,今天就从vc6开始,做个记录,学习一下. VC可以生成make文件(Project->Export Makefile),在设置好环境变量下,执行NMAKE ...
- Linux 组与用户
组: 添加: groupadd groupName -g groupID --> groupadd dba -g 502 删除: groupdel groupName ...
- Linux平台下使用rman进行oracle数据库迁移
实验目的:将oracle数据库从一台机器迁移到另外的一台机器(同为linux平台),设置为不同的路径,不同的实例名 源端: ORACLE_BASE=/u01/app/oracle ORACLE ...
- 几篇SIEM文章
http://infosecnirvana.com/tag/siem-rule-types/ http://www.tripwire.com/state-of-security/security-da ...