为未来的自己编写代码

2025-06-07

为未来的自己编写代码

我们都经历过这种情况。你写了一段代码,通读了一遍,觉得它很完美,因为当时你觉得它说得通。一年后再看同一段代码,你会发现它面目全非

我写的代码太完美了!😎
— 你,1 年前。

发推文


这是什么鬼?😡——
你,看看你一年前的代码。

发推文

问题在于,你写的代码是为现在的自己写的。相反,你需要为未来的自己写。本质上,你只需要问自己这个问题:“未来的我能理解这段代码的意图吗?”

以下是我多年来编写难以阅读的代码所学到的一些技巧。

不要试图打动自己

我喜欢写巧妙的代码。它让我感觉自己很聪明。直到一年后我回头看这些巧妙的代码,试图弄清楚它到底在做什么,以及为什么我没有用更简单、更标准的方式实现它。

所以,如果你想做一些令人印象深刻的事情,那就写一些可读性强的代码。毕竟,你可能在同一天从感觉自己像神一样变得一无所知。

每个程序员都有两种状态:左边面板上的人正在操作各种旋钮和开关,标题是“我是神”。右边面板上的人是一只呆呆地坐在电脑前的狗,标题是“我不知道自己在做什么”。

使用有意义的名字

我很难为我的变量、函数、模块等想出名字。甚至有这样一句流行语:

计算机科学中只有两件难事:缓存失效和命名。——
Phil Karlton

虽然命名是一项需要培养的技能,但我发现大多数人要么想得太少,要么想得太多。以下是我遵循的一些实用建议:

  • 避免使用诸如container或 之类的通用名称data
  • is对布尔值使用类似或的前缀has(即使在类型化语言中)。
  • 使用诸如get或之类的前缀create来表示函数的动作。
  • min使用类似或的前缀total来获得更具描述性的数字。
  • 创建数组时请使用适当的复数形式,例如users
  • 避免使用像 这样的单字母变量e,只需使用eventerror即可。
  • 不要害怕包含多个单词的长名称,例如getTotalDaysSinceLastLogin

最重要的是:尽可能减少潜在的混乱

分离你的条件

许多应用程序的核心是逻辑,它实际上就是你的if语句。这些语句的条件可能非常复杂。

在这个例子中,你需要多长时间才能理解其中的逻辑?



if (users[0] && posts.find(post => post.userId === users[0].id)) {
  showUserPost();
}


Enter fullscreen mode Exit fullscreen mode

时间在这里很重要。当然,我最终或许能弄清楚这段代码,但如果整个代码库都这样写,那么任何未来的维护者(包括你自己)都会费尽心思去理解它。

您可能急于在这里创建注释,但让我们通过将条件移到有意义的变量来改进代码本身。



const isUserPostCreated = users[0] && posts.find(post => post.userId === users[0].id);

if (isUserPostCreated) {
  showUserPost();
}


Enter fullscreen mode Exit fullscreen mode

如果我们添加另一个条件呢?创建另一个变量。



const isUserPostCreated = users[0] && posts.find(post => post.userId === users[0].id)
const isReaderLoggedIn = getReaderFromDatabase().isLoggedIn();

if (isUserPostCreated && isReaderLoggedIn) {
  showUserPost();
}


Enter fullscreen mode Exit fullscreen mode

现在,当未来的你查看这段代码时,你将能够大声读出整个语句并准确理解发生了什么。

创建具有单一职责的函数

我犯过编写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;
}


Enter fullscreen mode Exit fullscreen mode

从某种意义上说,这确实遵循了单一职责原则,因为它只验证用户名。然而,我们在这里运行了多个验证,包括查询数据库。我们也无法完全确定它是否有效。

我们可以做的是将这个函数分解成其他更小的函数。



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;
}


Enter fullscreen mode Exit fullscreen mode

现在这些较小的功能更容易改变、移动和测试。


未来你会感谢你自己

以及其他可能使用您所编写的代码的人。

这篇文章和你的经历有关联吗?你对代码的可读性还有其他建议吗?我一直在努力提升自己,所以请随时给我发推文或在下方留言。

:本文最初发表于我的个人博客。我将其转载至此,以飨广大的 DEV 社区。

文章来源:https://dev.to/sunnysingh/writing-code-for-your-future-self-3da2
PREV
给开发人员的设计技巧
NEXT
服务器端渲染的优势和起源