普通视图

发现新文章,点击刷新页面。
今天 — 2025年5月19日首页

译:整洁代码心理学—为何我们写出混乱的React组件

作者 ikonan
2025年5月19日 13:13

译:整洁代码心理学—为何我们写出混乱的React组件

编者注:==这篇文章探讨了开发者为何明知整洁代码重要却仍写出混乱 React 组件的心理原因==。1) ==认知负荷陷阱==让我们在压力下选择快速方案而非最佳实践;2) ==沉没成本谬误==使我们不愿重构已有代码;3) ==复杂性偏见==导致过早优化和过度设计;4) ==决策疲劳==限制了我们持续做出最佳编码决策的能力。文章提出了渐进式开发、心理安全环境和"童子军规则"等实用策略来改善代码质量。

我们都知道应该写整洁代码。我们读过相关书籍,参加过讲座,也认同各种原则。但不知为何,我们仍然会写出混乱的 React 组件。原因不在于我们的技术能力,而在于我们的心理。

认知负荷陷阱

考虑这个常见场景:

const UserDashboard = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [filter, setFilter] = useState("");
  const [sortBy, setSortBy] = useState("name");
  const [page, setPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);
  useEffect(() => {
    fetchUsers();
  }, [filter, sortBy, page]);
  const fetchUsers = async () => {
    try {
      setLoading(true);
      const response = await fetch(
        `/api/users?filter=${filter}&sort=${sortBy}&page=${page}`
      );
      const data = await response.json();
      setUsers(data.users);
      setTotalPages(data.totalPages);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  const handleFilterChange = (e) => setFilter(e.target.value);
  const handleSortChange = (e) => setSortBy(e.target.value);
  const handlePageChange = (newPage) => setPage(newPage);
  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;
  return (
    <div>
      <FilterBar
        filter={filter}
        onFilterChange={handleFilterChange}
        sortBy={sortBy}
        onSortChange={handleSortChange}
      />
      <UserList users={users} />
      <Pagination
        currentPage={page}
        totalPages={totalPages}
        onPageChange={handlePageChange}
      />
    </div>
  );
};

这个组件不算糟糕,但也不够好。它承担了太多职责,处理了太多关注点,维护起来会很困难。然而,这正是我们在压力下或试图快速推进时会写出的那种组件。

为何我们写出混乱代码

1. 计划谬误

我们总是低估任务所需时间。这导致:

  • 赶工期
  • 走捷径
  • 跳过重构
  • 忽视最佳实践

2. 沉没成本谬误

一旦写出代码,我们就因以下原因不愿修改它:

  • 已经投入了时间
  • 对自己的解决方案有情感依赖
  • 害怕破坏现有功能

3. 复杂性偏见

我们常常:

  • 过度复杂化简单解决方案
  • 添加未来可能需要的功能
  • 过早创建抽象
  • 为可能永远不会出现的边缘情况编写代码

4. 决策疲劳与认知负荷

神经科学研究表明我们大脑的决策能力有限。Diederich 和 Trueblood(2018)的研究显示:

  • 开发者连续编码 2 小时后错误率增加 30%
  • 组件中每增加一个状态变量,认知负荷增加 37%
  • 复杂组件会触发类似多任务处理的"神经切换成本"

这解释了为何我们常常:

  • 选择快速方案而非适当抽象
  • 复制代码而非重构现有逻辑
  • 留下 TODO 注释而非立即解决问题

Sweller(1988)的==认知负荷理论==表明,工作记忆只能同时保存 4±1 个信息块。当我们的组件管理多个关注点(数据获取、状态管理、UI 渲染)时,就会超出这个限制,代码质量就会下降。

打破循环

1. 从小处着手并迭代

与其写上面那种庞然大物,我们可以从以下开始:

const UserDashboard = () => {
  const { users, loading, error } = useUsers();
  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;
  return <UserList users={users} />;
};

然后根据需要逐步添加功能:

const UserDashboard = () => {
  const { users, loading, error } = useUsers();
  const { filter, setFilter } = useFilter();
  const { sortBy, setSortBy } = useSort();
  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;
  return (
    <div>
      <FilterBar
        filter={filter}
        onFilterChange={setFilter}
        sortBy={sortBy}
        onSortChange={setSortBy}
      />{" "}
      <UserList users={users} />{" "}
    </div>
  );
};

2. 创造心理安全感

  • 留出重构时间
  • 允许承认错误
  • 鼓励代码审查
  • 表彰整洁代码范例

3. 使用"童子军规则"

让代码比你发现时更整洁。这意味着:

  • 看到小问题就修复
  • 逐步重构
  • 随时记录
  • 与团队分享知识

实用策略

1. 五分钟规则

写任何代码前先问:

  • 最简单的可行方案是什么?
  • 我能在 5 分钟内解决这个问题吗?
  • 最少需要做什么?

2. "代码审查"测试

提交代码前问:

  • 我会自豪地在代码审查中展示这个吗?
  • 这是解决问题最整洁的方式吗?
  • 怎样才能让这段代码更好?

3. "未来的我"测试

考虑:

  • 未来的我能理解这段代码吗?
  • 未来的我能轻松修改这段代码吗?
  • 未来的我会感谢现在的我写了这段代码吗?

还有:

  • 我能用一句话说明这个组件的职责吗?
  • 添加新功能需要修改超过 3 个文件吗?
  • 有任何"我当时在想什么?"的代码模式吗?

结论

写整洁代码不仅是技术能力问题,更是理解我们的心理偏见并努力克服它们。通过认识这些模式并实施这些策略,我们可以写出更好的代码,创建更易维护的应用。

记住:整洁代码不是追求完美,而是做出小而持续的改进,并意识到我们天生倾向于走捷径。

延伸阅读

书籍与概述

英文原文

昨天以前首页

译:自由实验你的代码—Git worktree

作者 ikonan
2025年5月17日 17:23

编者注: Git worktree 是 Git 提供的一个强大功能,它允许你在同一个仓库中同时处理多个分支,而不会干扰当前的工作环境。1) 通过创建新的 worktree,你可以并行处理多个任务,比如修复紧急 bug 和开发新功能。2) worktree 与主工作区完全隔离,你可以独立提交、推送和归档更改。3) 使用 worktree 可以避免频繁切换分支带来的混乱,保持工作区的整洁。本文详细介绍了 worktree 的使用场景和操作方法,帮助你更高效地管理 Git 仓库。

什么是 Git worktree

Git worktree 是 Git 仓库的链接副本,允许你同时检出多个分支。worktree 与主工作副本的路径不同,但它可以处于不同的状态和不同的分支上。Git 中新的 worktree 的优势在于,你可以进行与当前任务无关的更改,提交更改,然后在稍后合并它,而不会干扰你当前的工作环境。

来自 git-worktree 手册页的典型示例是,当你正在为项目开发一个令人兴奋的新功能时,你的项目经理告诉你需要一个紧急修复。问题是,你的工作仓库(你的“worktree”)因为正在开发一个主要的新功能而处于混乱状态。你不想将修复“偷偷”插入当前的冲刺中,也不愿意暂存更改以创建一个新的分支来进行修复。相反,你决定创建一个新的 worktree,以便在那里进行修复:

$ git branch | tee 
* dev 
  trunk 
$ git worktree add -b hotfix ~/code/hotfix trunk 
Preparing ../hotfix (identifier hotfix) HEAD is now at 62a2daf commit

上述命令的功能是从 trunk 分支创建一个名为 hotfix 的新分支,并将其作为一个独立的 worktree 放置在 ~/code/hotfix 目录中。此时,你可以将这个 worktree 当作主要的工作空间。你能够切换到该目录,进行紧急修复,提交修改,最后删除这个 worktree:

$ cd ~/code/hotfix 
$ sed -i 's/teh/the/' hello.txt 
$ git commit --all --message '紧急修复'

一旦你完成了紧急工作,你可以回到之前的任务。你可以控制何时将你的 hotfix 集成到主项目中。例如,你可以直接从它的 worktree 将更改推送到项目的远程仓库:

$ git push origin HEAD 
$ cd ~/code/myproject

或者你可以将 worktree 归档为 TAR 或 ZIP 文件:

$ cd ~/code/myproject 
$ git archive --format tar --output hotfix.tar master

或者你可以从单独的 worktree 中获取更改:

$ git worktree list 
/home/seth/code/myproject 15fca84 [dev] 
/home/seth/code/hotfix 09e585d [master]

从那里,你可以使用最适合你和你的团队的策略来合并你的更改。

列出活跃的 worktree

你可以使用 git worktree list 命令获取 worktree 的列表,并查看每个 worktree 检出的分支:

$ git worktree list 
/home/seth/code/myproject 15fca84 [dev] 
/home/seth/code/hotfix 09e585d [master]

你可以在任何一个 worktree 中使用这个命令。worktree 总是链接的(除非你手动移动它们,破坏 Git 定位 worktree 的能力,从而切断链接)。

移动一个 worktree

Git 在你的项目的 .git 目录中跟踪 worktree 的位置和状态:

$ cat ~/code/myproject/.git/worktrees/hotfix/gitdir /home/seth/code/hotfix/.git

如果你需要重新定位一个 worktree,你必须使用 git worktree move;否则,当 Git 尝试更新 worktree 的状态时,它会失败:

$ mkdir ~/Temp 
$ git worktree move hotfix ~/Temp 
$ git worktree list 
/home/seth/code/myproject 15fca84 [dev] 
/home/seth/Temp/hotfix 09e585d [master]

删除一个 worktree

当你完成工作后,你可以使用 remove 子命令删除它:

$ git worktree remove hotfix 
$ git worktree list 
/home/seth/code/myproject 15fca84 [dev]

为了确保你的 .git 目录是干净的,在删除 worktree 后使用 prune 子命令:

$ git worktree prune

何时使用 worktree

使用标签、书签、自动备份等功能时,需自行跟踪数据,否则易管理混乱。Git worktree 也同理,别频繁创建,避免副本过多。建议按需创建,完成任务、提交工作后及时删除,保持简洁专注。

重要的是,worktree 为你管理 Git 仓库提供了更大的灵活性。在需要时使用它们,再也不用为了检查另一个分支上的内容而匆忙保存工作状态。

英文原文

❌
❌