首页 › programming › 嵌套神课深读:把代码拉直

嵌套神课深读:把代码拉直

概述

在编程类视频的海洋里,绝大多数讲“代码可读性”的内容要么沦为实现风格的口水仗,要么停留在“要有注释”这种正确的废话。而 CodeAesthetic 的这支《Why You Shouldn't Nest Your Code》是一个罕见的例外:它用不到十分钟的篇幅,把一个每个程序员每天都在犯、却几乎没人系统讲过的问题——“嵌套是如何杀死可读性的”——讲成了有理论、有工具、有边界的完整论证。这条视频自 2022 年 8 月发布以来持续发酵,累计播放已达数百万量级,在 Hacker News、Reddit 的 r/programming 等社区反复被翻出来讨论,堪称“代码风格”这个老掉牙话题里最新的一条常青爆款。本文带你逐段拆解它的论证结构,补上它没来得及展开的理论源头,并对它略显标题党的部分做一次诚实的审查。

视频基本信息

项目 内容
视频标题 Why You Shouldn't Nest Your Code(为什么你不该嵌套你的代码)
频道 CodeAesthetic
发布时间 2022 年 8 月 30 日(据频道页面)
播放量 数百万量级,长期是该频道播放最高的视频之一(据频道页面与社区转载,未实时核验精确数字)
视频链接 https://www.youtube.com/watch?v=CFRhGnuXG-4
内容类型 代码风格 / 软件 craftsmanship 动画讲解

核心主张拆解:一条视频的五步论证

视频的叙事结构非常克制,全片围绕一个论点和两件工具展开,按顺序可以拆成五个要点。

要点一:嵌套把代码变成了“解谜游戏”

视频开场没有讲道理,而是直接放了一段典型代码:一个函数里,if 套着 for,for 里再套 if,最内层还有一个判断。随着缩进层层加深,代码的轮廓在屏幕上形成一个箭头的形状。这个视觉呈现本身就是全片第一个论点——“箭头反模式(arrow anti-pattern)”,这是软件工程社区流传已久的俗称,《代码大全》里称之为 "arrow code"。

作者指出:人类阅读代码时,本质上是在脑子里维护一个执行栈。每进一层嵌套,读者就要往认知栈里压入一个“当前处于什么条件、什么循环阶段”的状态;读到最内层的业务逻辑时,栈里已经压了三四层前置条件。而写代码的人离职以后,接手的人要为每一行最内层代码同时回答四个问题——“我在哪个函数里、在什么循环里、满足了什么条件、这个条件反过来意味着什么”。嵌套越深,解谜成本越高。

要点二:第一件工具——卫语句,把主流程拉回零缩进

视频给出的第一个解法是反转条件、提前返回(guard clauses,卫语句)。原代码里那种“条件满足才继续往下走”的写法,被改成“条件不满足就直接 return”:参数非法?返回。列表为空?返回。权限不足?返回。所有异常路径在前几行被清空之后,函数的主体——真正的那条“幸福路径”——从第三层缩进回到了零缩进,读者从上往下读是一条直线,不需要记住任何未闭合的状态。

这是全片信息密度最高的部分:作者强调卫语句改变的不是代码结构,而是阅读的叙事顺序。嵌套写法的隐含叙事是“先声明所有前提,再讲正事”;卫语句的叙事是“把所有会打断正事的破事先处理掉,然后心无旁骛地讲正事”。后者与人处理事情的直觉一致。

要点三:第二件工具——提取函数,守住单一抽象层级

当嵌套来自循环而非条件时,卫语句无能为力,视频随即祭出第二件工具:把嵌套块提取成独立函数。关键不在“提取”这个动作本身,而在作者随后的那条判据——一个函数内部的所有语句,应该处于同一个抽象层级。高层的编排语句和底层的字符处理语句混在一个函数里,是嵌套滋生的土壤;把它们分层装进不同函数,每层函数都变短、变平,函数名则充当了“压缩算法”,替读者把一整块逻辑压成一个词。

要点四:诚实的另一面——过度提取也是病

这条视频真正区别于同类“风格布道”的地方,在于它没有把自家工具吹成万能药。作者专门用一段演示了“提取成瘾”的反例:有人为了消灭所有缩进,把代码切成七八个只被调用一次的小函数,每个函数都得靠跳转才能看到下一行,函数名还起得云里雾里。作者给出的自检信号非常实用:当你给一个提取出来的函数起不出一个好名字时,多半说明你切错了边界——你压缩的不是逻辑,而是把阅读成本换了个地方收账。读代码的人省了缩进,却要在文件里来回跳转,总账反而更亏。

要点五:嵌套本身无罪,深埋控制流才是罪

全片的结论并非“零嵌套”。作者明确区分了两类嵌套:数据结构的嵌套(两层循环遍历矩阵、递归处理树形结构、对象套对象)与控制流的嵌套(条件套条件、条件套循环再套条件)。前者往往就是问题本身的结构,硬要拉平反而扭曲语义;后者才是真正需要警惕的对象。视频标题里那个略显粗暴的 "Shouldn't",落到实处是一句温和得多的主张:让嵌套服务于数据,而不是把控制流埋进深处。

知识与理论溯源:这条视频的学术底座

CodeAesthetic 的视频没有给出参考文献,但它论证链条上的每一环,都能在真实的软件工程文献里找到出处。

结构化编程的源头:Dijkstra 与 1968 年那封信。“用缩进代替跳转”的现代代码形态,起点通常追溯到 Edsger W. Dijkstra 发表于 1968 年《Communications of the ACM》的著名信件《Go To Statement Considered Harmful》。Dijkstra 的论点是:程序员的任务是把程序的静态文本与动态执行过程对应起来,而 goto 让两者的对应关系断裂。结构化编程用顺序、选择、循环三种结构取代了任意跳转——但一个容易被忽略的推论是:嵌套深度就是读者需要跟踪的动态路径长度。箭头反模式某种程度上是 goto 被消灭后,复杂度换了个方向卷土重来。

圈复杂度:把“嵌套多坏”变成一个数字。1976 年,IBM 的 Thomas J. McCabe 在 IEEE《Transactions on Software Engineering》上发表论文《A Complexity Measure》,提出圈复杂度(cyclomatic complexity):等于控制流图中的线性独立路径数,工程上近似为“分支判断数加一”。McCabe 建议以 10 为警戒阈值。嵌套对圈复杂度是指数级放大器——每嵌一层二分支的条件,路径总数就翻一倍,四层嵌套就是一个函数里藏着十六条可能的执行路线。今天 SonarQube 等工具里那条“复杂度过高”的告警,源头就是这篇论文。

更早的文本智慧:Kernighan 与 Plauger。1974 年,Brian Kernighan(后来写 Unix 和 K&R C 的那位)与 P. J. Plauger 出版《The Elements of Programming Style》,从真实教材代码里挑错,核心格言是“写清楚,别耍聪明(Write clearly – don't be too clever)”,并明确提倡用提前退出简化控制结构。卫语句在整整四十八年前就已经是教科书建议——这条视频不过是把它翻译成了动画。

风起云涌的工业规范。Robert C. Martin 2008 年的《Clean Code》把“函数要小、每个函数一个抽象层级”变成了一代人的默认设定;Martin Fowler 的《Refactoring》目录里干脆躺着两个现成的重构条目——"Replace Nested Conditional with Guard Clauses"(以卫语句取代嵌套条件)与 Extract Function,视频的两件工具在这本书里各有一个正式户口。而 Linux 内核的官方编码风格文档写得更直白:“如果你需要超过三层的缩进,那你已经完蛋了,先修你的程序。”Google 等公司的风格指南也有类似的深度限制。

认知科学的账本。为什么是三四层而不是十层?答案在人的硬件。George Miller 1956 年的经典论文提出工作记忆容量约为 7±2 个组块,Nelson Cowan 2001 年的再研究把这个数字下修到 4±1。John Sweller 1988 年提出的认知负荷理论(Cognitive Load Theory)进一步解释:嵌套代码迫使读者同时维持多层未闭合的条件状态,这属于典型的“内在负荷”叠加,一旦超过工作记忆容量,理解就退化为来回滚动查证。视频里“读代码像解谜”的比喻,学术表述就是:嵌套深度超过了工作记忆的组块预算。

批判性审查:哪些站得住,哪些是标题党

站得住的部分。“深嵌套损害可读性”在工业界近乎没有反方:从内核到谷歌的风格指南、从 SonarQube 到各家 linter 的默认规则,全部站在同一侧。这不是巧合,而是四十年代码评审实践收敛出的共识。卫语句与提取函数两项技术,在 Fowler 的重构目录里有明确的操作步骤与适用条件,属于证据充分的标准技艺。

有争议的部分。McCabe 的"10"这个阈值是经验值,不是自然常数。后续的软件工程实证研究(如对复杂度度量的多项再检验工作)发现:圈复杂度与缺陷率的相关性,在统计上控制了代码规模之后会明显减弱——代码长的模块本来就更容易出 bug,未必是因为“分支多”本身。换句话说,“嵌套深=缺陷多”的因果链是成立的,但强度被一些流行文章夸大了。此外,不同语言文化差异巨大:Go 语言满屏的 if err != nil 本质上就是卫语句哲学的极致展开,用好了是直线叙事,写多了也制造海量的检查噪声;Python 有 match、上下文管理器等折叠控制流的语法;C 语言里 goto cleanup 反而是处理资源释放的惯用法。风格纪律无法脱离语言生态一刀切——这也是视频没有展开、但读者应当心里有数的一层。

标题党的部分。"Why You Shouldn't Nest Your Code" 这个标题,按传播规律被社交媒体进一步压缩成了“所有嵌套都是坏的”。但只要看完视频就会知道,作者自己明确为数据嵌套和合理循环留了位置,甚至专门批评了为消灭缩进而过度提取的做法。这是一条典型的“标题负责吸引,内容负责精确”的知识视频——标题里的 "Shouldn't",实际强度大概相当于 Fowler 书目录里那句温和的“以卫语句取代嵌套条件”。另一个值得挑剔的点是:视频没有讨论大型代码库中“提取函数”的真实代价——函数数量爆炸后,模块边界的维护成本、调试时调用栈的深度,都是它两件工具的隐性账单。

认知提升与实用启示

第一,把“缩进层数”当作免费的代码异味探测器。你不需要看懂一段代码的业务逻辑,就能判断它是否危险:数缩进。任何函数出现第四层缩进,就值得在代码评审里问一句“这里的条件能反转吗?这块能提取吗?”。这是成本最低的评审检查项——不依赖领域知识,一秒钟出结果。配合编辑器里的缩进参考线或彩虹缩进插件,代码坏味道会直接在视觉上“鼓出来”。

第二,用“卫语句优先”做一次刻意练习。从自己的项目里挑一段三层以上的老代码,做一次只包含两个动作的重构:反转条件提前返回、提取嵌套块为函数。完成后对比前后 diff,你会发现主路径的行数往往不变,但缩进几乎归零——这正是这项练习要建立的手感:可读性的提升常常不来自重写,而来自调整语句的出场顺序。检查在前、正事在后,主流程自然成直线。

第三,用“命名测试”守住提取的边界。每次提取函数前,先试着给它起一个不含 "and"、不含 "or"、不需要斜杠分隔的名字。起得出,说明这块逻辑本来就是一件事,提取是压缩;起不出,说明你正在把两件事强行打包或者把一件事拦腰截断,先回头拉平再切。这个十秒钟的自检,能挡住视频里批评的那类“提取成瘾”——毕竟过度提取的代码和深嵌套的代码,读者砸进去的是同一种认知成本。

视频论证结构图

flowchart TD
    A["深嵌套代码<br/>箭头反模式"] --> B["认知负荷超载<br/>状态层层压栈"]
    B --> C["工具一<br/>卫语句提前返回"]
    B --> D["工具二<br/>提取函数分层"]
    C --> E["主流程零缩进<br/>直线阅读"]
    D --> E
    E --> F["过度提取陷阱<br/>命名困难是信号"]
    F --> G["平衡点<br/>嵌数据不嵌控制流"]
    G --> H["回报<br/>缺陷更少 维护更省"]

延伸阅读

  1. Refactoring: Replace Nested Conditional with Guard Clauses — Martin Fowler 重构目录中“卫语句”条目的官方操作步骤,视频第一件工具的正式出处。
  2. Linux Kernel Coding Style — Linux 内核官方风格文档,"三层缩进即完蛋"的原文所在,工业级风格纪律的极简版。

参考来源

  1. Why You Shouldn't Nest Your Code — YouTube — 本文解读的主体视频,CodeAesthetic 频道 2022 年 8 月发布(统计数据未实时核验,据频道页面)。
  2. Cyclomatic Complexity — Wikipedia — McCabe 1976 年圈复杂度指标与阈值 10 的背景介绍。
  3. Considered harmful — Wikipedia — Dijkstra 1968 年《Go To Statement Considered Harmful》信件的历史脉络与影响。
  4. Refactoring Catalog — refactoring.com — Fowler《重构》在线目录,含卫语句与提取函数条目。
  5. Linux Kernel Coding Style — kernel.org — Linux 内核缩进规范原文。

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入