如何为代码起好的名字

您所在的位置:网站首页 hpb300代号和名称 如何为代码起好的名字

如何为代码起好的名字

2023-05-31 14:37| 来源: 网络整理| 查看: 265

原文

命名非常重要。如果你的代码至少要被阅读一次(如果只有你自己),那么名字将在你处理代码的能力中发挥重要作用。变量名、函数名、类名、接口中的名称,这些都是让代码了解其工作的无价方法。在工作中的代码审阅期间,我对团队成员关于良好命名的问题非常挑剔—兄弟们,对此我深表遗憾!-但我相信这会影响我们的代码质量。

即使有其他方法可以知道一段代码在做什么,例如文档,好的名称是一个非常有效的途径,可以至少从二个方面传达有关代码的信息:

好名字会即时告诉周围代码中的问题,而不是查阅文档并跟随它寻找代码的方向,命名可以快速改进。你只需手动或使用工具(例如流行的ClangTidy)进行快速修复,即可更新代码中的一些名称,而且如果代码构建成功,你几乎可以确定它将通过测试。

这篇文章旨在提供如何选择好名字的指引。我已经从史提夫Code Complete(代码大全)的参考书中抽取了其中一些指导原则(如果你还没有阅读,我建议你停止阅读这篇文章,或者为此正在做的任何事情,并开始阅读这本书🙂 ). 还有其他一些我从与同事的讨论、建议和代码审阅中学习到。几年来,我自己通过阅读和编写代码来尝试不同的事情。

我们将从讲述如何避免坏名字开始,然后专注于如何挑选好名字。

不要做任何不合法命名的事情

有些名字是不允许在C++中使用的,让我们把它们放在一边。

除了使用标准保留的名称(如“int”)来停止编译外,名称中的一些底线(_)组合将在不合法的情况下进行编译,因为它们是为编译程序或标准库实现者保留的。使用它们可能与它们声明的对象或程序冲突,导致细微的错误和意外的行为。

以下是为编译程序和标准库实现者保留的名称:

任何包含二个连续底线的名称(__)纽约名称以一个底线开始,其后紧跟一个大写字母(_isOk, isOk_too, _IsNotOk)以一个底线开始并在全局名字空间中的名称。

所以不要考虑使用这些名字,因为它们可能会给你带来困难。

不要浪费信息

当你考虑它时,你的代码完全知道它在做什么。事实上,只有一个最清楚:它尽可能忠实地执行其中的内容!

尽可能多地保留这些信息。换言之,这是关于不通过混淆代码来浪费信息。值得注意的是,通常信息隐藏是通过封装来鼓励的。但在这种情况下,披露的信息才是你的目标。

因此,限制使用缩写。缩写和首字母缩写便于书写但难以阅读。常言道,代码一写多读。现在,为了使代码更清晰,不必系统地拼出所有首字母缩写,一些重复的未经缩写的代码甚至会损害可读性。例如,似乎在代码中合理地使用“VAT”,而不是每次使用时都编写valueAddedTax,因为每个人都知道VAT是什么。

如何选择代码中是否使用首字母缩写?一个好的经验法则是,如果应用程序的最终用户理解某个特定的缩写或首字母缩写,则可以在代码中使用该缩写或首字母缩写,因为这表示域中的每个人都知道其含义。

不要尝试优化最少的字符数。在论坛上,你可以看到一些人认为他们的方法更好,因为它涉及较少的输入。但是,还有什么比这更让人费神的事,几次击键,或几分钟盯着代码试图找出它?

这对于函数和方法名称尤其适用,你可以根据需要设置其长度。研究表明(Rees 1982),函数和方法的名称可以合理地增加到35个字符,这听上去非常像。

然而,函数名的长度也可能由于以下不好的原因而变得过于冗长:

如果一个函数的名称太长是因为该函数做了太多的事情,那么要做的修复不是在名称级别,而是通过将其分解为多个逻辑部分,将其自身作为一个函数级别。当函数名包含已经由其参数类型表示的多余信息时,它们会被人为地膨胀。例如: void saveEmployee(Employee const& employee);

可以重命名为:

void save(Employee const& employee);

这会在调用点产生更自然的代码:

save(manager);

相对于:

saveEmployee(manager);

这与接口原则和ADL(涉及在调用中删除多余的名称空间)的方向相同,后者将成为专用文章的主题。

名称包含不希望的信息的另一个原因是它包含否定。以下代码: if (isNotValid(id)) {

可以通过使用肯定的名称来改进:

if (!isValid(id)) {

现在我们已经排除了一定数量的不好的命名实践,让我们关注如何挑选好的名字。

选择与抽象级别一致的名称

如前一篇文章所述,尊重抽象层次是许多良好实践的根本。其中之一就是好的命名。

好名字是与周围代码的抽象级别一致的名字。正如在关于抽象层次的文章中所解释的,这可以用不同的方式来描述:一个好的名字表示代码在做什么,而不是它是如何做的。

为了说明这一点,让我们以一个计算公司所有员工工资的函数为例。该函数返回一组将键(雇员)与值(薪水)关联的结果。这段代码的假想实现者已经看了Chandler Carruth关于数据结构性能的讨论,并决定放弃映射,取而代之的是成对向量。

一个不好的函数名,它会关注函数是如何实现的:

std::vector computeSalariesPairVector();

这种函数名的问题在于,它表示函数以成对向量的形式计算结果,而不是专注于它所做的事情,即计算员工的工资。对此的快速修复方法是将名称替换为以下内容:

std::vector computeEmployeeSalaries();

这将从一些实现细节中解放调用点,让代码的读者专注于代码的意图。

尊重抽象层次对变量和对象名有着有趣的影响。在许多情况下,在代码中,变量和对象表示的东西比它们的类型所暗示的更抽象。

例如,int通常不仅仅表示int:它可以表示一个人的年龄或集合中元素的数量。或者类型为Employee的特定对象可以表示团队的经理。或者std::vector可以表示纽约上个月观测到的日平均气温。(当然,这在非常低级的代码(比如添加两个int)中不适用,或者在使用强类型的地方也不适用)。

在这种情况下,你希望以变量所代表的内容命名变量,而不是以其类型命名。应该将int变量命名为“age”,而不是“i”。你可以将上述Employee命名为“manager”,而不仅仅是“employee”。你应该把向量命名为“temperatures”而不是“doubles”。

这似乎很明显,但至少有两种情况我们通常忽略了应用这一准则:迭代器和模板类型。

尽管迭代器会随着算法和范围库的发展而消失,但是仍然需要一些迭代器,而且许多迭代器仍然存在于今天的代码中。例如,让我们收集金融产品支付或收到的现金流。这些现金流有的是正的,有的是负的。我们要找回第一笔现金流,所以第一笔是正的。下面是编写此代码的第一次尝试:

std::vector flows = ... auto it = std::find_if(flows.begin(), flows.end(), isPositive); std::cout ParsedType result; // ... perform the parsing ... return result; }

比较这两段代码。你认为哪一个更容易合作?

你可能认为这有很大的不同,也可能认为没有,但可以肯定的是,第二段代码中包含了更多的文档,而且是免费的。

一般来说,这是正确的命名:一旦有免费的午餐,让我们抓住它。

相关文章

尊重抽象层次

了解STL < algorithm >的重要性



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3