长名太长

哈Ha! 我向您介绍鲍勃·尼斯特罗姆(Bob Nystrom)的文章“长名字很长”


Google所做的聪明事之一就是严格的代码审查。 在允许您对主分支进行更改之前,应至少在两个方向上进行每次更改。 首先,团队中的某人进行例行检查,以确保代码执行了应有的工作。


但是随后,当检查代码的可读性时,发生第二步。 这样可以确保其他开发人员将来能够支持此代码。 该代码易于理解和维护吗? 该代码是否与语言的风格和习惯用法相符? 该代码是否有据可查?


在Google上使用Dart语言的势头正逐渐兴起,而我在处理此类代码方面做了大量工作。 对于语言开发人员来说,这是一个非常令人兴奋的过程。 我获得了人们如何使用Dart的第一手资料,这对Dart的开发确实很有用。 我对哪些错误很常见以及哪些功能被大量使用有了一个更清晰的认识。 我觉得自己像一个民族志学家,一本关于土著人生活的日记。


但是,无论如何,情况并非如此。 该死的,甚至不是飞镖。 我想说的是我在许多代码中看到的东西,以及让我发疯的东西: 过长的名字


是的,名称可能太短。 在那个年代C要求只有外部标识符在前六个字符之前是唯一的; 当尚未完成自动完成时; 当每个按键都像在雪地上爬坡时,这是一个问题。 我很高兴我们现在生活在一个未来主义的乌托邦中,那里像pidxcrpmx3这样的键盘屁很少。


但是钟摆向另一个方向摆动得太远了。 我们不必是海明威,我们也不必是田纳西·威廉姆斯。 太长的名称还会损害使用它们的代码的清晰度。 太长的变量名会使您对其执行的操作蒙上阴影。 代码变得难以直观地扫描。 为了满足代码宽度的要求,出现了其他换行符,这些换行符中断了代码的逻辑流程。 长方法名隐藏了它们同样重要的参数列表。 长变量会因重用而烦人,这会导致方法或级联的链条拉伸。


我看到变量名超过60个字符。 您可以在其中放置一个haiku或koan(并且可能比您选择的名称更能启发读者)。 但是不要担心,我在这里为您提供帮助。


选择一个好名字


编程中的任何名称都有两个目标:


  • 名称应明确 :您需要知道它指的是什么。
  • 名称必须准确 :您需要知道它不适用于什么。

名称达到这些目标后,所有其他字符都将失去作用。 这是在代码中命名时要使用的一些准则:


1.避免在变量或参数类型中明确指定的单词


如果您的语言具有静态类型系统,则用户通常会知道变量的类型。 通常,方法很短,因此即使查看无法立即假定类型的局部变量,也无法查看代码,或者无法查看静态代码分析的某个地方-很少需要多看几行以上确定变量的类型。


因此,不必在变量名中指出类型。 我们只是放弃了匈牙利符号放手,忘记


 // : 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) 

这样可以使呼叫的读取效果更好:


 mergeTableCells(tableCells); sortEventsUsingComparator(events, comparator); 

就是我,还是这里有回声?


2.避免使用不会混淆名称的单词


有些人倾向于将对某事的了解全部推入一个变量名。 请记住,该名称是一个标识符 :它表示定义的位置。 这不是读者可能想要了解的有关该对象的所有内容的详尽目录。 定义会更好。 这个名字只会将他引导到那里。


当我看到名称为recentlyUpdatedAnnualSalesBid ,我问自己:


  • 是否有不是最新的更新的年度销售订单?
  • 最近有没有更新的年度销售要求?
  • 是否有最近更新的年度非销售申请?
  • 是否有不是出价的最近更新的年度销售数据?

如果对这些问题中的至少一个答案为“否”,则通常表示名称中有一个多余的单词。


 // : finalBattleMostDangerousBossMonster; weaklingFirstEncounterMonster; // : boss; firstMonster; 

当然,您可能走得太远。 将第一个示例缩短为bid可能含糊。 但是,如果有疑问,就这样保留。 如果名称是引起冲突的名称或不正确,则以后可以随时添加其他分类。 但是,您不太可能稍后再回来修剪所有这些多余的脂肪。


3.避免使用上下文中清楚的词语。


在本段中,我可以使用“ I”一词,因为您知道该文本来自Bob Nystrom。 我不需要在这里不断重复“鲍勃·内斯特罗姆”(尽管鲍勃·内斯特罗姆以这种方式加强鲍勃·内斯特罗姆的诱惑)。 该代码的工作原理完全相同。 方法或字段出现在类的上下文中。 变量在方法的上下文中发生。 将此上下文视为理所当然,请勿重复。


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

实际上,这意味着名称的嵌入越深,其周围的环境就越多。 结果,该名称将更短。 结果,您可以看到一个模式:狭窄区域中的标识符名称较短。


4.避免使用没有意义的词。


我经常在游戏行业看到这种错误。 一些开发人员屈从于诱惑,并夸大了变量的名称,在“严重的业务”中添加了一些词。 他们认为这使他们的代码更重要,因此也使他们更重要。


在大多数情况下,这些词对开发人员而言没有任何有意义的信息。 通常,怀疑是基于以下词语: datastateamountvaluemanagerengineobjectentityinstance


一个好名字会在读者的脑海中描绘一幅画。 我们称其为“经理”,不会向读者提供有关此对象应该做什么的任何信息。 它会进行绩效评估计算吗? 任命晋升员工?


问问自己:“如果我把这个词带走,这个名字会意味着相同吗?” 如果是,那么这个词就没关系-从岛上赶出去。


将手册应用于...华夫饼


为了让您了解这些规则在实践中的工作方式,以下是一个违反所有规则的示例。 这个人为设计的示例与真实代码非常相似,在代码审查中我经常遇到这种情况。


 class DeliciousBelgianWaffleObject { void garnishDeliciousBelgianWaffleWithStrawberryList( List<Strawberry> strawberryList) { ... } } 

由于参数的类型,我们知道该方法接受草莓列表(#1)。 让我们从名称中删除此信息:


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

如果程序中没有任何其他国籍的比利时华夫饼或华夫饼,那么我们可以安全地丢弃所有形容词(#2):


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

此方法位于WaffleObject内部,因此从上下文中我们可以确切知道它将要装饰什么(#3):


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

显然,这是一个对象。 一切都是面向对象编程中的对象(#4):


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

现在好多了。


我认为这些是非常简单的建议。 您有权认为担心这种琐事是没有用的。 但是我相信命名是我们编程时执行的最基本的任务之一。 名称是我们强加在无形的比特海洋(即计算机)上的结构。

Source: https://habr.com/ru/post/zh-CN450986/


All Articles