译:整洁代码心理学—为何我们写出混乱的React组件
译:整洁代码心理学—为何我们写出混乱的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 个文件吗?
- 有任何"我当时在想什么?"的代码模式吗?
结论
写整洁代码不仅是技术能力问题,更是理解我们的心理偏见并努力克服它们。通过认识这些模式并实施这些策略,我们可以写出更好的代码,创建更易维护的应用。
记住:整洁代码不是追求完美,而是做出小而持续的改进,并意识到我们天生倾向于走捷径。