我喜欢这样的代码:代码逻辑直接了当,几乎不会隐藏缺陷;代码的依赖关系非常简单,维护起来非常容易;有完善的错误异常处理逻辑;性能要足够好,以至于不会引诱别人做出一些没必要的调优。
整洁的代码应该是除了自己之外,可以由其他的人轻易的阅读和扩展。应当有详尽的单元测试以及验收测试。有意义的命名,而且只提供一种而非多种做一件事的途径,拥有明确的定义和提供清晰、尽量少的API--公共的方法。
有意义的命名
“命名”在软件中是随处可见的,我们给变量,方法、参数、类以及包命名。选个好名字需要花时间的,但是带来的好处也是显而易见的。选个好名字,做到名副其实,而且一旦发现更好的名称,立即换掉它。
int d;//消逝的时间,以日记
这里的 d 什么业没有说明,并没有引起对时间消失的感觉,没能计量的对象以及计量的单位友好的说明。
选择本意的名称更让人理解和修改。
以上的代码逻辑并不复杂,问题不在于代码的简介度,而是在于代码的复杂度,没有说明此方法要做什么事。此段函数要求我们去了解一下问题:theList中的元素是什么?theList零下标中的元素意义何在?值4的意义是什么?如何使用返回的列表?
问题的答案并没有在上下文中体现出来,但是这是必须的。如果我们在开发扫雷游戏,此函数的目的获取已经被标记过得单元格。heList是扫雷面板的单元格集合,那就应该将其名称改为 gameBoard。盘面的每个单元都用一个二维数组表示,零下标是一种状态值,恰好值4表示该种状态为“已标记”,那么代码应该这样优化。
避免误导
必须避免留下掩藏代码本意的错误线索,应当避免使用与本意相悖的词。
别用 accountList 来指代一组账号,除非它真的是 List 类型。 List 在Java中有特殊的含义,如果包含这组账号的容器并非是List,就会给引起错误的判断。因此用 accountGroup 或者 bunchOfAccouns, 甚至使用 accounts 都要好很多。
提防使用细微之处较小的名称。相区分模块之中某处的 EfficientHandingOfStringsController 和另外一处EfficientStorageOfStringsController,会话多少时间呢?以同样的方式拼写出同样的概览才是正确打开的方式,拼写前后不一致就是误导。避免使用“O” 和 “l”作为变量,这通常看起来像“0”和“1”
做有意义的区分
让你的命名给读者提供导向作者意图的线索,做有意义的区分。
该函数的目的在于将a1的字符数组中的值复制到字符数组a2当中,但是该方法签名并没体现这一点,通过方法签名无法得知是a1向a2复制还是s2向a1复制。如果把参数名改为 source 和 destination,这个函数就会整洁的多,这也符合“明确”、“清晰”的原则。
废话是另一种没有意义的区分。
如果有一个定义机场信息的类 AirportInfo 或者 AirportData类,尽管他们的名称不同,意思却无差别。Info 和 Data 就像 a\an\the一样是意义含混的废话(注意,只要体现出有意义的区分,使用a和the这样的前缀就没有错)。
变量 nameString 会比 name好吗? flightNo 会币 flight 好吗? id 会比 idNumber好吗?getSegments(); getSegmentList(): getSegmentInfo(); 程序员并不知道在何种情况下调用那个函数。
如果缺少明确约定,变量 moneyAmount和money就没有区别,customerInfo和customer没有区别,acountData 和account没却别,theMessage 和 messge没区别,pnrNo 和 pnr 没有区别,flightNo 和 flight 没区别,officeNo 和 office 没区别。要区分名称,就要以读者能够鉴别不同之处的的方式来区分。
使用可搜索的名称
单字母名称和数字常量有个问题,就是很难在大片文章中找出来。
找MAX_PASSENGERSIZE_PER_ORDER(每个订单乘客的最大人数)很容易,但是你要在整个工程中搜索出有效的数字9就比较麻烦了。
长名称由于短名称,搜索到的名称胜于自造编码代写的名称。
单字母名称仅用于短方法的本地变量中。名称的长短应与其作用于大小相呼应。若变量或常量可能在代码中多处使用,则应该赋予以便于搜索的名称。采用能表达意图的名称,貌似拉长了函数代码,但是想想看,WORK_DAYS_PER_WEEK 要比数字 5好定位的多,二我们的代码中也就只剩下了体会作者意图的代码。
不要添加没用的语境
编码太多,无需在自找麻烦。把类型和作用域编进名称里面,徒增代码量和了解代码的负担。
应该把类和函数做的足够小,消除对成员前缀的需要。使用能够高亮现实的编辑环境(现在的IDE几乎都支持)。
Passenger类用于定义乘客信息实体。第一个声明的类中所有的字段均添加了passenger前缀,难道它比第二类更好吗?
添加有意的语境
很少有名称能自我说明--多数多不能!你需要有良好的命名类、函数或者名称空间来放置名称,给读者提供语境。如果没有这坐,给名称添加前缀就是终极大招了。设想你有名为 firstName、 lastName、street、 city、houseNumber、state、zipcode等的变量。当他们搁在一块的时候明显构成了一个地址。不过假设只是在某个地方中看见其中某个孤零零的变量呢?还会理所当然的认为是个地址吗?
这个时候这需要添加前缀 addrFirstName、addrLastName、addrCity等,以此提供语境。
其他
类和对象名称应该是名词或名词短语,如Customer、Account以及AddressParser之类的,秘避免使用 Manage ,Data 或者Info类。
方法名应该是动词或者动词短语,如 post、get、match、save、insert、deleteIterm。属性的访问、修改以及断言等方法应该根据值命名,并依照 JavaBean标准加上 get、set 、is等前缀。
在重载构造方法的时候,使用描述了参数的静态工厂方法名。
给每一个抽象概念选一个词,并且一以贯之。例如,使用fetch、retrieve、get给在多个类中的同种方法命名,都能表达同一种意思,但是你怎么能记住在哪一个类中使用的哪一种命名的方法呢?现在IDE通常会有调用对象的方法列别,但是方法列表上却没有相应的注释,如果你的方法签名能过明确告诉你这个方法是干什么,那么你真是太幸运了。不过,不幸的是绝大多数的老代码并不会这样做。函数名称应该是对无二的,遵循同一种规则,而且要保持一致,你这样会节省很多花时间。
此外,避免同一术语表示不同概念,同一概念使用不同的词来表示,这样基本就造成了双关语了。MongoDB 的 save() 、insert()以及insertAll()方法就用这问题。
使用解决方案领域的名称、使用源自所设问题领域的名称。
言到意到、意到言到!
后记
取名字的难点在于需要良好的描述技巧和文化背景。这不仅是一种技术、商业、管理问题,更是一种教学问题。然而,这个领域内的绝大多人都没有做得更好。