认知负荷很重要纽带X科技

认知负荷很重要

26分钟 ·
播放数8
·
评论数0

本集简介: 本集播客深入探讨软件开发中的一个核心但常被忽视的概念——认知负荷。我们将揭示为何许多流行的“最佳实践”反而增加了开发人员的思维负担,导致效率低下、错误频发,并阻碍新成员快速融入项目。我们将讨论如何识别并减少代码中不必要的外在认知负荷,从而构建出更易于理解、维护和扩展的软件系统。

----------------------------------------------------------------

本集要点:

什么是认知负荷?

◦ 认知负荷指的是开发人员完成一项任务所需的思考量。

◦ 它不是一个抽象概念,而是人类基本的认知局限

◦ 人类平均工作记忆只能容纳大约四个“信息块”;一旦超过这个阈值,理解事物就会变得非常困难,导致认知过载(🤯)。

◦ 我们花费更多时间阅读和理解代码,而非编写代码,因此持续关注代码中的认知负荷至关重要。

两种认知负荷类型:

内在认知负荷 (Intrinsic Cognitive Load): 由任务固有的难度引起,无法减少,是软件开发的核心。

外在认知负荷 (Extraneous Cognitive Load): 由信息呈现方式造成,与任务本身不直接相关。这种认知负荷可以大大减少,也是本播客的重点。

高认知负荷的常见陷阱及应对策略:

复杂的条件语句: 过度链式的 &&|| 语句会导致认知过载。解决方案: 引入有意义的中间变量来简化逻辑,降低理解成本。

嵌套的 if 语句: 深层嵌套的 if 语句迫使开发者记住所有前置条件。解决方案: 采用早期返回 (Early Returns) 模式,使开发者可以专注于“正常路径”。

“继承噩梦”: 过于复杂的继承层次结构会使理解功能变得困难,需要在多个父类之间跳转才能掌握完整逻辑。解决方案: 提倡优先选择组合而非继承 (Prefer Composition Over Inheritance)

过多的小方法、类或模块: 遵循“方法应短于15行”等信条常导致“浅层模块”(接口复杂而功能简单)。这会增加理解项目各模块之间交互的难度。解决方案: 设计深层模块 (Deep Modules),即提供强大功能但接口简单的组件,将复杂性隐藏在内部(例如 UNIX I/O 接口)。

对 DRY 原则和单一职责原则的误解:

▪ “模块应只负责一件事”常被误解,导致创建过多“浅层模块”,其名称和接口比实现本身更耗费心力。

更准确的理解: 一个模块应该对一个且只有一个用户或利益相关者负责,这与业务影响相关,而非功能数量。

滥用 DRY (Do Not Repeat Yourself): 过度消除重复可能在不相关的组件之间造成紧密耦合,导致牵一发而动全身。“少量复制胜过少量依赖” (A little copying is better than a little dependency)

过多的浅层微服务: 即使在微服务架构中,过多细碎的“浅层微服务”也会导致“分布式巨石”,极大地增加调试和维护的认知负荷(例如一个五人团队维护17个微服务的案例)。解决方案: 优先选择设计精良、模块真正隔离的单体应用,仅当开发团队规模扩大或需要独立部署时,再考虑引入网络层分离模块。

功能丰富的编程语言: 编程语言中过多的新特性,尤其是非正交的特性,会增加学习和理解成本,迫使开发者不仅要理解代码,还要理解为何选择该特性来解决问题。C++ 的历史演进就是一个例子。

业务逻辑与 HTTP 状态码: 将业务细节(如 JWT 过期、权限不足)映射到自定义 HTTP 状态码(如 401, 403, 418),会给前端和 QA 工程师带来额外的认知负荷。解决方案: 优先在响应体中直接返回自描述的字符串代码(例如 {"code": "jwt_has_expired"}),以保持各方思维清晰。

与框架的紧密耦合: 框架中的“魔法”要求新开发者投入数月学习。过度依赖框架可能在新需求出现时成为阻碍。解决方案: 尽可能以框架无关的方式编写核心业务逻辑,将框架作为库使用,而非将业务逻辑置于框架内部。

分层架构的代价: 诸如 Hexagonal/Onion 架构等分层设计,虽然初看合理,但常常引入不必要的间接性(“胶水代码”)和认知负荷,尤其是在需求频繁变化的场景下。它也并不能保证数据库等底层组件的快速替换。解决方案: 遵循更基本的原则,如依赖反转原则 (Dependency Inversion Principle),仅在有明确、实际的扩展点需求时才添加抽象层。

领域驱动设计 (DDD) 的误区: DDD 常被误解为专注于解决方案空间(如文件夹结构),而非问题空间(如通用语言、有界上下文)。这种主观解释可能导致不必要的认知负荷和争议。建议: Team Topologies 提供了一个更易于理解的框架,有助于跨团队分担认知负荷。

熟悉项目中的认知负荷:

熟悉不等于简单。开发者对自己熟悉的代码往往难以发现其复杂性。

“新来的小孩”视角: 鼓励新加入项目的开发者批评代码,他们的“新鲜”视角能帮助发现那些让团队成员习以为常的认知负荷点。

衡量困惑: 通过结对编程等方式观察新成员的困惑程度,如果连续困惑超过约40分钟,则说明代码有改进空间。

目标: 保持低认知负荷,让新成员在加入公司后的几小时内就能开始贡献价值。

核心思想与总结:

减少所有超出工作固有复杂性的认知负荷

◦ 如 Rob Pike、Andrej Karpathy、Elon Musk 和 Addy Osmani 等业内专家所强调,最佳的代码不是最优雅或最复杂的,而是未来的开发者(包括你自己在内)能够快速理解的代码

--------------------------------------------------------------------------------

引用与资源:

原始资料: GitHub - zakirullin/cognitive-load

推荐书籍:软件设计哲学 (A Philosophy of Software Design)》by John K. Ousterhout

相关文章:

◦ 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”

◦ “Why I Hate Frameworks”

概念/原则: 依赖反转原则、Team Topologies。