原文:On the Importance of Naming in Programming | Wasp
原标题:On the Importance of Naming in Programming
作者:Martin Sosic
在故事中,你经常会发现主题是有一个强大的恶魔,只有知道它的真名才能控制它。一旦英雄通过狡猾的对话或者调查古老的卷轴找到了那个名字,他们就可以扭转局势并驱逐恶魔!
我坚信编写代码也并没有太大的差别:通过为函数、变量和其他结构找到好的名称,我们能够真正认识到我们正在解决的问题的本质。获得清晰度的结果不仅仅是通过好的名称,还有更干净的代码和改进的架构。
<img src="https://fs.lwmc.net/uploads/2023/11/1699289368991-202311070049530.webp" alt="The power of correct naming in programming" style="zoom: 25%;" />
我敢说,编写干净代码的90%要做的仅仅是正确地命名。听起来很简单,但实际上并非如此!
让我们来看几个例子。
// 给定一个人的名字和姓氏,返回所有匹配人员的人口统计数据。
async function demo (a, b) {
const c = await users(a, b);
return [
avg(c.map(a => a.info[0])),
median(c.map(a => a.info[1]))
];
}
这段代码有什么问题?
demo
的名称非常模糊:它可以表示“拆除”,也可以表示“做一个演示/展示”等等。a
、b
和c
的命名完全没有信息量。map
内部的lambda函数中重复使用了变量a
,遮蔽了作为函数参数的a
,这使得读者感到困惑,并且在将来修改代码时更容易出错,引用了错误的变量。users()
函数的结果中,字段.info
的名称没有给我们任何关于它包含的内容的信息,这一点因为其元素是通过它们的位置来访问的而变得更糟,这也隐藏了关于它们的任何信息,使我们的代码在它们的排序发生变化时容易默默地出错。让我们来修复它:
async function fetchDemographicStatsForFirstAndLastName (
firstName, lastName
) {
const users = await fetchUsersByFirstAndLastName(
firstName, lastName
);
return {
averageAge: avg(users.map(u => u.stats.age)),
medianSalary: median(users.map(u => u.stats.salary))
};
}
我们做了什么?
fetch
,这表示它执行了一些IO操作(输入/输出,在这里是从数据库获取数据),这对于知道IO相对于纯代码来说比较慢/昂贵很有帮助。users
来表示获取到的用户,而不是像usersWithSpecifiedFirstAndLastName
或fetchedUsers
这样更长的名称:不需要使用更长的名称,因为这个变量作用域非常局部、生命周期很短,并且周围上下文足以清楚地说明它的含义。u
这可能看起来不太合适。但是,在这里,这是完美的:这个变量的生命周期极短,并且从上下文可以清楚知道它代表什么。而且,我们特意选择字母u
,是因为它是user
的首字母,这样可以让这层关联更加明显。averageAge
和medianSalary
。现在任何使用我们的函数的代码就不需要依赖结果中项目的顺序,同时也更易读、更具信息量。最后,注意函数前面不再需要注释了。实际上,注释已经不再需要了:从函数名称和参数就可以完全清楚函数的作用!
// 找到一个空闲的机器并使用它,如果需要的话,创建一个新的机器。
// 然后在该机器上,使用给定的Docker镜像和设置命令设置新的工作进程。
// 最后,在该工作进程上开始执行任务并返回其ID。
async function getJobId (
machineType, machineRegion,
workerDockerImage, workerSetupCmd,
jobDescription
) {
...
}
在这个示例中,我们忽略了实现细节,只关注名称和参数的正确性。
这段代码有什么问题?
getJobId(...)
→ 你不会期望它花费很长时间或做所有它实际上做的事情,这是不好的。好的,这个问题很容易解决,让我们给它一个更好的名称!
async function procureFreeMachineAndSetUpTheDockerWorkerThenStartExecutingTheJob (
machineType, machineRegion,
workerDockerImage, workerSetupCmd,
jobDescription
) {
...
}
哎呀,这是一个又长又复杂的名称。但事实上,如果我们不失去关于这个函数做什么以及我们可以从中期望什么有价值的信息,我们无法将其缩短。因此,我们陷入了困境,找不到更好的名称!现在怎么办?
问题是,如果没有干净的代码支持,你就无法给出一个好的名称。因此,一个糟糕的名称不仅仅是一个命名错误,而且通常也是一个指示着问题代码的指标,一个设计失败。代码如此有问题,以至于你甚至不知道该给它起什么名字→没有一个直接的名字可以给它,因为它不是一个直接的代码!
在我们的例子中,问题在于这个函数一次尝试做太多事情。一个长的名称和许多参数是这个问题的指标,尽管在某些情况下这些可能是可以接受的。更强烈的标志是在名称中使用了“和”和“然后”这样的词,以及可以通过前缀(如machine
、worker
)进行分组的参数名称。
这里的解决方案是通过将函数分解为多个较小的函数来清理代码:
async function procureFreeMachine (type, region) { ... }
async function setUpDockerWorker (machineId, dockerImage, setupCmd) { ... }
async function startExecutingJob (workerId, jobDescription) { ... }
但是让我们退一步 - 什么是糟糕的名字,什么是好的名字?这意味着什么,我们如何识别它们?
好的名字不会误导,不会省略,也不会假设。
一个好的名字应该能给你一个关于变量包含的内容或函数作用的好的理解。一个好的名字会告诉你所有需要知道的,或者会告诉你足够的信息让你知道下一步应该去哪里查找。它不会让你猜测,或者困惑。它不会误导你。一个好的名字是明显的,是可以预期的。它是一致的。不会过于创新。它不会假设读者不太可能拥有的上下文或知识。
此外,上下文至关重要:你不能在没有读取的上下文的情况下评估名字。verifyOrganizationChainCredentials
可能是一个糟糕的名字,也可能是一个很好的名字。a
可能是一个很好的名字,也可能是一个糟糕的名字。这取决于故事,环境,以及代码解决的问题。名字讲述一个故事,它们需要像故事一样相互配合。
Authorization
,但是它用于身份验证!而这两者并不相同:身份验证是关于确认你的身份,而授权是关于授予权限。更多的信息可以在这里找到:https://stackoverflow.com/questions/30062024/why-is-the-http-header-for-authentication-called-authorization .最好的建议可能不是给出一个名字,而是去找出一个名字。你不应该创造一个全新的名字,就像你在给宠物或孩子取名一样;你应该寻找你所命名的事物的本质,名字应该基于这个本质自然呈现出来。如果你不喜欢你找到的名字,那意味着你不喜欢你所命名的事物,你应该通过改进你的代码设计来改变这个事物(就像我们在第二个例子中所做的那样)。
<img src="https://fs.lwmc.net/uploads/2023/10/1698157426331-202310242223171.webp" alt="You shouldn't name your variables the same way you name your pets, and vice versa" style="zoom:25%;" />
服务器
这个词,那就没有理由开始使用后端
这个词。同样,如果你使用服务器
作为一个术语,你可能不应该选择前端
:相反,你可能会想使用客户端
,这是一个与服务器
更紧密相关的术语。is
(例如isAuthEnabled
)ensure
,它们只会在尚未设置的情况下做某事(例如分配资源)(例如ensureServerIsRunning
)。如果你在命名的时候遇到困难,做以下事情:
不要过于纠结于一开始就找出完美的名字→可以多次迭代你的代码,每次迭代都会提高你的代码和名字。
一旦你开始深思熟虑地命名,你会看到它是如何改变你的代码审查过程的:焦点从查看实现细节转移到首先查看名称。
当我在进行代码审查时,我会有一个主要的思考:“这个名字清晰吗?”。从那里开始,整个审查演变并结果在清晰的代码。
检查一个名字是一个pressure
点,可以解开其背后的所有混乱点。看到不好的命名,你迟早会发现,并存着糟糕的代码。
如果你还没有读过的话,我建议你阅读Robert Martin的《Clean Code》这本书。它有一章关于命名的内容,还深入讲解了如何编写让你和其他人都喜欢阅读和维护的代码。
此外,还有一个关于命名困难的流行笑话 - TwoHardThings
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。