为未来的自己编写代码
我们都经历过这种情况。你写了一段代码,通读了一遍,觉得它很完美,因为当时你觉得它说得通。一年后再看同一段代码,你会发现它面目全非。
我写的代码太完美了!😎
— 你,1 年前。
这是什么鬼?😡——
你,看看你一年前的代码。
问题在于,你写的代码是为现在的自己写的。相反,你需要为未来的自己写。本质上,你只需要问自己这个问题:“未来的我能理解这段代码的意图吗?”
以下是我多年来编写难以阅读的代码所学到的一些技巧。
不要试图打动自己
我喜欢写巧妙的代码。它让我感觉自己很聪明。直到一年后我回头看这些巧妙的代码,试图弄清楚它到底在做什么,以及为什么我没有用更简单、更标准的方式实现它。
所以,如果你想做一些令人印象深刻的事情,那就写一些可读性强的代码。毕竟,你可能在同一天从感觉自己像神一样变得一无所知。
使用有意义的名字
我很难为我的变量、函数、模块等想出名字。甚至有这样一句流行语:
计算机科学中只有两件难事:缓存失效和命名。——
Phil Karlton
虽然命名是一项需要培养的技能,但我发现大多数人要么想得太少,要么想得太多。以下是我遵循的一些实用建议:
- 避免使用诸如
container
或 之类的通用名称data
。 is
对布尔值使用类似或的前缀has
(即使在类型化语言中)。- 使用诸如
get
或之类的前缀create
来表示函数的动作。 min
使用类似或的前缀total
来获得更具描述性的数字。- 创建数组时请使用适当的复数形式,例如
users
。 - 避免使用像 这样的单字母变量
e
,只需使用event
或error
即可。 - 不要害怕包含多个单词的长名称,例如
getTotalDaysSinceLastLogin
。
最重要的是:尽可能减少潜在的混乱。
分离你的条件
许多应用程序的核心是逻辑,它实际上就是你的if
语句。这些语句的条件可能非常复杂。
在这个例子中,你需要多长时间才能理解其中的逻辑?
if (users[0] && posts.find(post => post.userId === users[0].id)) {
showUserPost();
}
时间在这里很重要。当然,我最终或许能弄清楚这段代码,但如果整个代码库都这样写,那么任何未来的维护者(包括你自己)都会费尽心思去理解它。
您可能急于在这里创建注释,但让我们通过将条件移到有意义的变量来改进代码本身。
const isUserPostCreated = users[0] && posts.find(post => post.userId === users[0].id);
if (isUserPostCreated) {
showUserPost();
}
如果我们添加另一个条件呢?创建另一个变量。
const isUserPostCreated = users[0] && posts.find(post => post.userId === users[0].id)
const isReaderLoggedIn = getReaderFromDatabase().isLoggedIn();
if (isUserPostCreated && isReaderLoggedIn) {
showUserPost();
}
现在,当未来的你查看这段代码时,你将能够大声读出整个语句并准确理解发生了什么。
创建具有单一职责的函数
我犯过编写init()
数百行代码、执行多项操作的函数的错误。这很容易做到,但不幸的是,之后会生成一些无法修改的代码。
对此,一个简单的建议是遵循所谓的单一责任原则。这意味着一个函数应该只负责一小部分功能。
让我们以验证用户名为例。
function validateUsername(username) {
// Invalid if username is over 20 characters.
if (username.length > 20) {
return false;
}
// Invalid if username has non-alphanumeric characters.
if (/[^a-z0-9]/gi.test(username)) {
return false;
}
// Invalid if user already exists in database.
if (db.query('SELECT id FROM users WHERE username = ', username)) {
return false;
}
// Otherwise valid!
return true;
}
从某种意义上说,这确实遵循了单一职责原则,因为它只验证用户名。然而,我们在这里运行了多个验证,包括查询数据库。我们也无法完全确定它是否有效。
我们可以做的是将这个函数分解成其他更小的函数。
function validateUsernameLength(username) {
return username.length <= 20;
}
function validateAlphanumeric(string) {
return !/[^a-z0-9]/gi.test(string);
}
function checkUsernameExists(username) {
return db.query('SELECT id FROM users WHERE username = ', username);
}
function validateUsername(username) {
const isLengthValid = validateUsernameLength(username);
const isAlphanumeric = validateAlphanumeric(username);
const isUsernameTaken = checkUsernameExists(username);
return isLengthValid && isAlphanumeric && !isUsernameTaken;
}
现在这些较小的功能更容易改变、移动和测试。
未来你会感谢你自己
以及其他可能使用您所编写的代码的人。
这篇文章和你的经历有关联吗?你对代码的可读性还有其他建议吗?我一直在努力提升自己,所以请随时给我发推文或在下方留言。
文章来源:https://dev.to/sunnysingh/writing-code-for-your-future-self-3da2注:本文最初发表于我的个人博客。我将其转载至此,以飨广大的 DEV 社区。