欢迎回来
登录你的知识库账户
忘记密码?
还没有账户?立即注册
创建账户
注册你的专属知识库
已有账户?去登录
找回密码
输入注册邮箱获取验证码
返回登录
请输入图片中的验证码以继续注册
加载中...
取消
新建收藏
手动添加你喜欢的内容
取消
编辑头像与昵称
上传新头像或修改你的显示昵称
支持 JPG/PNG,最大 2MB
取消

问题反馈

notebasewww.notebase.cn
控制台
内容库
动态
管理
账户
U
用户
--
在线
v0.8.7 · 知识库
笔记
KnowledgeBase
网络无边,知识有迹。
0笔记
0工具
30推荐

分类导航

按主题直达

编辑精选

站内用户贡献 · 真实笔记

最新收录

每日更新
继续浏览全部内容 →
>
笔记
0
加载中...
工具
0
此页用于记录用户反馈问题后的每一次改进
笔记用法

“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。

md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。

要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。

工具用法

在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。

要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。

工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。

隐藏笔记

写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。

适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。

数据安全

你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。

技术

全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。

理念

这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。

原则

不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。

更多

产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。

举报

如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。

趋势
// 点击导航加载发现
归档
// 归档为空
最近浏览
// 暂无浏览记录
发布
// 加载中...
用户发布
// 加载中...
用户管理
// 加载中...
访问统计
// 加载中...
内容审核
// 加载中...
个人信息
// 加载中...
返回首页

认知负荷才是关键:软件设计的根本度量

1970/1/1编程开发

软件设计的核心目标是降低认知负荷,而非追逐教条式的最佳实践。

引言:为什么大多数最佳实践都失败了

技术圈充斥着各种流行语和最佳实践,但其中大部分最终都失败了。它们失败的原因在于:这些理念是被想象出来的,而非基于真实世界的事实。它们建立在美学偏好和主观判断之上,而非客观规律。

我们需要更根本的东西——某种不可能出错的度量标准。

当我们在阅读代码时感到困惑,这种困惑会直接转化为时间和金钱的浪费。困惑的根源是什么?是高认知负荷。这不是什么玄乎的抽象概念,而是人类认知的根本生理约束。它不是被想象出来的,而是真实存在且可以感知的。

我们阅读和理解代码的时间远超编写代码的时间,因此应该持续自问:我们是否在代码中嵌入了过多的认知负荷?

在 AI 时代,这一点变得尤为重要——我们需要用自己有限的脑力去处理大量 LLM 生成的代码。

什么是认知负荷

认知负荷指开发者在完成任务时需要投入的思考量。阅读代码时,需要将变量值、控制流逻辑、调用序列等信息放入工作记忆。普通人平均只能同时记住大约 4 个信息块。一旦认知负荷达到这个阈值,理解就会变得异常困难。

假设我们被要求在一个完全陌生的项目中修复问题,有人告诉我们贡献这个项目的开发者非常聪明。项目里满是酷炫的架构、花哨的库和时髦的技术——换句话说,作者为我们创造了高认知负荷。

我们应该尽可能降低项目中他人的认知负荷。

注:本文使用"认知负荷"的非正式含义;它有时与科学上的 Cognitive Load 概念重合,但我们不确定在多大程度上吻合。

认知负荷的类型

  • 内在负荷——由任务本身的固有难度引起。无法减少,是软件开发的核心本质。
  • 外在负荷——由信息呈现方式创造。由与任务不直接相关的因素引起(如作者的古怪风格),可以大幅降低。

我们聚焦于外在负荷,直接看具体例子。用以下标签标识认知负荷水平:

  • 🧠:工作记忆清新,零负荷
  • 🧠++:两个信息在工作记忆中,负荷上升
  • 🤯:认知过载,超过4个信息块

真实人脑远比这复杂,但这个简化模型足够说明问题。

复杂条件表达式

js
if (val > someConstant // 🧠+
&& (condition2 || condition3) // 🧠+++ 之前条件须为真,且c2或c3有一个为真
&& (condition4 && !condition5)) { // 🤯 到这里已经乱了
...
}

解决方案:引入带语义的中间变量:

js
const isValid = val > someConstant;
const isAllowed = condition2 || condition3;
const isSecure = condition4 && !condition5;

// 🧠 无需记住每个条件,有描述性变量
if (isValid && isAllowed && isSecure) {
...
}

嵌套 if vs 提前返回

嵌套版本:

js
if (isValid) { // 🧠+ 只有合法输入才执行内部代码
if (isSecure) { // 🧠++ 只对合法且安全的输入做处理
doStuff(); // 🧠+++
}
}

提前返回版本:

js
if (!isValid) return;
if (!isSecure) return;

// 🧠 无需考虑前置条件,能到这里说明一切就绪
doStuff(); // 🧠+

我们可以只关注快乐路径,从而将各种前置条件从工作记忆中释放。

继承噩梦

场景:我们被要求为管理员用户修改一些功能。

js
AdminController extends UserController extends GuestController extends BaseController

🧠 哦,部分功能在 BaseController 里,去看看:

🧠+ 基本角色机制在 GuestController 中引入:

🧠++ 部分逻辑在 UserController 中被修改过:

🧠+++ 终于到了 AdminController,开始写代码!

🧠++++ 等等,还有一个 SuperuserController 继承了 AdminController。修改 AdminController 可能破坏子类,先去 SuperuserController 看看:

🤯

优先使用组合而非继承——相关材料已经很多,无需赘述。

过小的方法、类或模块

方法、类、模块此处可互换。

"方法应小于15行"或"类应该小"之类的戒律,其实是错的。

深模块 vs 浅模块

  • 深模块:简单接口,复杂功能
  • 浅模块:接口相对于其提供的少量功能而言过于复杂

过多的浅模块会让项目难以理解。我们不但要记住每个模块的职责,还要记住它们之间的所有交互。理解浅模块的目的,必须先查看所有相关模块的功能——在浅模块之间跳转极耗心智。线性思维对我们更自然。

信息隐藏至关重要,而浅模块恰恰无法隐藏足够的复杂度。

实际案例:两个项目对比

作者有两份约 5000 行的个人项目:

  • 项目一:80个浅类
  • 项目二:7个深类

一年半未维护后回来,项目一极难解开80个类之间的交互——需要重建巨量认知负荷才能开始编码;而项目二能快速理解,因为只有少数深类和简单接口。

最好的组件是那些提供强大功能却拥有简单接口的组件。
—— John Ousterhout,《软件设计的哲学》

Unix I/O 接口:深模块的经典范式

Unix I/O 接口极其简单,仅5个基本调用:

open(path, flags, permissions)
read(fd, buffer, count)
write(fd, buffer, count)
lseek(fd, offset, referencePosition)
close(fd)

现代实现有数十万行代码,大量复杂性被隐藏在底层,但接口简单得易用如初。

这个深模块例子来自 John Ousterhout 的《A Philosophy of Software Design》。这本书不仅触及了软件开发复杂性的本质,还提供了对 Parnas 经典论文《On the Criteria To Be Used in Decomposing Systems into Modules》最精彩的诠释。两者都是必读。

延伸阅读:

  • 《A Philosophy of Software Design vs Clean Code》
  • 《It's probably time to stop recommending Clean Code》
  • 《Small Functions considered Harmful》

重要的东西应该大——肉眼可见的重要性

如果允许关键函数更大("不修边幅"),就能在函数海中一眼辨认——它们大,自然显眼。

图片来源:Carson Gross 的《Codin' Dirty》文章,那里有深函数的真实案例。

注意:我们并非提倡臃肿的上帝对象及过多职责——那完全是误读。

关于"单一职责"的滥觞

我们经常根据模糊的"一个模块应该只对一个(且仅一个)东西负责"原则,制造大量浅模块。

但什么才是那模糊的"一个东西"?

实例化一个对象算一件事吧?那 MetricsProviderFactoryFactory 似乎也没问题。

然而,这类类的名字和接口往往比它们整个实现更耗费心智——这算什么抽象?显然出问题了。

我们修改系统是为了满足用户和利益相关者的需求。我们在...

核心结论

  1. 认知负荷是人类认知的根本约束,不是可选的风格偏好。
  2. 降低外在认知负荷是设计的第一要务——它可被大幅削减。
  3. 警惕教条:方法长度、类大小等武断规则往往适得其反。
  4. 偏爱深模块:强大功能 + 简单接口 = 最优设计。
  5. 在 AI 时代,低认知负荷的代码比以往更重要——我们每天都要亲自审查大量 AI 生成的代码。

原文链接:https://minds.md/zakirullin/cognitive

编写使用方法
Markdown 格式 · Ctrl+Enter 确定
新建笔记
预览
数据表格
点击单元格编辑 · Tab 移动
A1fx
Sheet1
BIH1H2≡🔗</>
隐私提醒

取消
编辑工具
取消