规则:命名变量时,即使使用动态类型的语言,也不要将其类型编码为名称。
需要静态和动态示例
在上一篇文章中,我谈到了良好命名的一般规则 。 在此,我简短地谈到了不将类型编码为变量名的想法。 但是,在选择这些通用规则时,我只考虑了与语言类型无关的事物。
语言可以是静态或动态类型。 它们的类型取决于其定义或分配。
对于静态和动态类型的语言,实际上都不要在名称中编码类型,这是一个很好的规则,但是两者之间的原因有所不同。 出于这个原因,我想另外发表一篇文章,重点介绍该规则及其原因。
静态类型语言
在Java之类的静态类型语言中,我们必须在定义变量时声明其类型。 因此,如果我想建立一个整数列表,我会写:
final List<Integer> integerList = new ArrayList<>();
请注意此处固有的信息重复。 我已经通知我的读者,我正在用List<Integer>
创建一个整数List<Integer>
,我不需要通过命名变量integerList
来再次执行此操作。 这是一个容易想到的名字,但是没有添加任何新信息,也没有告诉读者整数实际代表什么。 我可以使用以下名称来改进:
final List<Integer> primesList = new ArrayList<>();
现在,读者可以很容易地看出这是质数的列表,但是我仍然包括有关它是列表的重复信息。 这使名称面临潜在的风险,另一位开发人员意识到所有素数都是唯一的,并在将来更改类型。 现在,我们得出的定义具有误导性,例如:
final Set<Integer> primesList = new TreeSet<>();
由于Set
和List
的用法完全不同,因此该变量的读者会感到困惑。 尽管此变量的定义站点提供了正确的信息,但如果距离其使用站点还有很长的路要走,那么读者将被认为是谎言。
public class Example {
private final Set<Integer> primesList =
new HashSet<>(); // This is the definition site
// ...
// A very long class full of code
// ...
private int doSomething () {
//...
this .primesList.add(prime); // Use-site: Here the name is misleading
//...
}
}
如果这里有错误,我们会使此代码的调试更加复杂。 对于使用站点的读者来说,可以对该对象进行排序,按索引访问,以及一堆其他不存在的功能。
显然,令人沮丧的是第二个作者没有更新名称以匹配类型的更改,但这并不意外。 这种变化经常发生在现实世界中。
并行数据通常是软件工程中问题的根源,因为保持同步具有挑战性。 拥有唯一的真理来源通常是良好系统设计中的优先事项,并且在良好的编程中也是如此(对于编写代码注释也是如此,我将在以后的文章中介绍)。 在静态类型的语言中,我们将来可以通过不对类型进行两次编码来证明我们的名称。
我最好调用上述函数primes
,使用名称的复数表示它是一个集合。 看起来像:
final Set<Integer> primes = new TreeSet<>();
在动态类型语言中
在像python这样的动态类型语言中,定义变量时不必声明变量的类型。 而是在分配时设置类型。 想象一下,我正在将Duck对象的集合传递给类似这样的函数:
def quack_all_ducks (ducksList) :
for duck in ducksList:
duck.quack()
在这里,我非常有意地探讨了动态类型语言的一个重要功能,即鸭子类型 (如果它走路或说话像鸭子一样,出于所有密集目的,它就是鸭子)。 这个想法是,在quack_all
函数中,我实际上并不在乎输入是否为列表,甚至是否包含鸭子。 在此函数中,我真正关心的是,我可以遍历给定的项目,并且可以为每个项目调用quack()
方法。 此处对单词List
和duck
编码都限制了此功能的功能。 我放弃了使用动态类型语言的主要优势之一。
此方法将对传递的所有内容调用quack; 甚至是鹅 该代码可以正确执行,但对于读者而言,这是意外的(而且调试起来更困难- 为什么我的鹅都嘎嘎嘎嘎响? )。 例如:
def on_loud_noise (pond_area) :
birds = [pond_area.get_all_ducks()] + [pond_area.get_all_geese()]
quack_all_ducks(birds)
#...
如果不进一步研究代码,这也使鹅很震惊。 简洁代码的症结在于使编写者付出了更多工作,以简化读者的生活。
命名参数quackables
会更好。 这表示它是一个遍历多个的迭代(集合),并且每个内容都可以被quacked
。 看起来像:
def quack_all_quackables (quackables) :
for quackable in quackables:
quackable.quack()
现在, quack_all
函数可用于可能会发出嘎嘎声的任何东西,例如鹅或天鹅的集合。 在动态类型语言中,将类型编码为名称会抵消鸭子输入的能力。
现在,我们的呼叫站点将如下所示:
def on_loud_noise (pond_area) :
birds = [pond_area.get_all_ducks()] + [pond_area.get_all_geese()]
quack_all_quackables(birds)
#...
自从鹅大吼大叫以来,这对于读者来说更加清晰,他们也会被大吵大闹。
From: https://hackernoon.com/why-you-should-always-avoid-encoding-type-into-names-f62y37ba