代码是第二门自然语言 — 阅读策略可以照搬
这一章讲三件事: 「编程需要数学脑」这个流行假设被三种证据轮流拆台;阅读代码和阅读文本在大脑里有多像; 以及把语文阅读的七个策略逐个翻译成读代码的动作。 它给第 05 章的「深读流程」补上科学地基,再往上盖一层方法论。
1. 全景:三路证据,一个结论
证据一(脑成像):读代码激活的脑区里,有一片是读语言用的
证据二(认知测验):预测编程水平的,语言能力 > 数学能力
证据三(眼动):读代码的眼动模式和读文本高度相似
↓ 三路合流
阅读代码 ≈ 第二种自然语言阅读
↓ 那么——
语文课练出来的阅读策略,可以整箱搬过来用
图说:这一章前半是证据,后半是把证据兑换成方法。
2. 证据一:读代码时,语言区亮了
先交代工具。大脑不同区域各管一摊,神经学家布罗 德曼 1909 年就把大脑皮层划成了 52 个区(布罗德曼分区,今天仍按编号称呼)1。功能性磁共振成像仪(fMRI)靠测脑部血流量来判断哪些区正在干活——任务越吃哪块,哪块供血越多2。
2014 年,西格蒙德(Siegmund)第一次拿 fMRI 研究编程:让被试读排序、查找这类常见算法的 Java 实现,但把所有变量名换成无意义的名字——逼被试没法靠名字抄近路,只能硬读3。
结果:程序理解激活了五个脑区,全在左脑。其中 BA6、BA40 管工作记忆和注意力(注意力,即大脑决定把有限的劲往哪儿使的能力),在情理之中;意外的是 BA21、BA44、BA47——它们是处理自然语言的区域4。要知道变量名已经被故意搅浑了,语言区照样亮——说明被试在把代码里的关键字当「词」来读,和读文章读句子用的是同一套装置5。
3. 证据二:预测编程能力,语言赢了数学
普拉特(Prat)的研究更扎心。她招了 36 名学生,让他们通过在线平台学 Python,同时用标准化测验量出每个人的数学能力、语言能力、工作记忆容量和推理能力,再看哪项最能预测编程成绩6。
结果和行业直觉正好相反7:
| 认知能力 | 能解释的编程成绩差异 |
|---|---|
| 数学(计算能力) | 仅 2% |
| 语言能力 | 17% |
| 工作记忆 + 推理 | 34%(在所有指标——衡量所用的计量项——里最强) |
顺带说,「能解释成绩差异的 2%」在统计里叫方差——这个比例越低,说明这项能力和成绩关系越小。数学能力——整个行业最迷信的那一项——几乎和学编程的速度无关;语言能力才是它最稳的预测指标。学习速度一项,语言能力的预测力尤其突出8。书里自己都感叹:高校把计算机系归在理工科,程序员的圈子文化推崇数学,而数据站在另一边9。
4. 证据三:眼动也像
眼动仪(记录视线落在屏幕哪里)给出的第三个佐证10:
- 新手读普通文本时,约八成眼球运动是线性(按固定顺序一步一步来、不来回跳)推进的;读代码时这个比例降到七成半——读代码本来就更「跳」,不足为奇;
- 真正有意思的是另一个发现:程序员读代码的最初三成时间里,扫过了七成以上的代码行——先扫一遍、再决定细读哪里,和拿起报纸先扫标题是同一个动作;
- 新手比老手读得更「逐行」,而且更爱追着调用栈(函数一层层调下去的链条)跑——这更像在学习怎么读,而不是在读11。
5. 把语文课搬过来:七个策略
既然装置重叠,方法就能搬。阅读研究总结过七种文本理解策略,书里逐个给它们配了代码版用法12。每个策略两三句,先看清单:
| 策略 | 语文版 | 代码版 |
|---|---|---|
| 激活 | 想想已知背景再读 | 读前先花固定时间扫代码、列出见到的概念 |
| 监测 | 觉察「这段没读懂」 | 给有把握的行打勾、没把握的打问号 |
| 确定重要性 | 找中心句 | 标出对程序影响最大的那几行 |
| 推断 | 补全言外之意 | 从变量名猜它装的是什么 |
| 视觉化 | 画情节图 | 画操作表、追踪变量值 |
| 提问 | 带着问题读 | 追问设计决策及其代价 |
| 摘要 | 概括段落大意 | 用自然语言写下这段代码干什么 |
三条容易忽略的细则。激活:扫视产出的是「这段代码里有哪些概念和语法」的清单,遇到陌生概念先停下学概念、再回来读代码——边读边现学概念两头都做不好,因为现学占用的正是读代码要用的那个工作记忆13。监测:问号行不只是自留地,它还是求助的最佳话术——「第 37 到 42 行我没看懂」远比「这段我看不懂」让对方能下手14。确定重要性:简单程序大约 10 行关键代码,复杂程序 25 行左右;团队各自标一遍再对答案,分歧不是要消灭的噪音,是了解彼此关注的窗口15。
6. 主走查:对一段真代码跑完七步
拿书里自带的例子当走查对象——一个叫 zipWith 的 JavaScript 函数(它拿一个函数 f 和两个列表,逐对喂给 f,凑出结果列表)16:
zipWith: function (f, as, bs) {
var length = Math.min(as.length, bs.length);
var zs = [];
for (var i = 0; i < length; i++) {
zs[i] = f(as[i], bs[i]);
}
return zs;
}
按七步走一遍(每一步右边是这步的真实产出):
- 激活:定时十分钟扫读。产出:这是 JS;见到
f、as、bs、zs、Math.min;没见到任何领域词——这是一段纯机制代码。 - 监测:打勾——for 循环、数组取下标;打问号——「为什么长度要取 min?」
- 确定重要性:全函数的心脏是
zs[i] = f(as[i], bs[i]),其余都是给它服务的。 - 推断:
f被调用(后面带括号)→ 是函数;as、bs被取下标(as[i])→ 是列表;zs先空后逐格塞 → 也是列表。注意这步完全没靠名字——as/bs本身无意义,推断全靠行为。 - 视觉化:列一张操作表(每个标识符执行过什么操作),上面第 4 步的产出就是表的行。回看问号行也解了:min 取短者长度,保证
i不越过较短列表的末尾。 - 提问:核心概念是「把函数作为值传来传去」;作者决策是不检查两个列表谁长谁短,代价是长列表的尾部被静默丢弃——换成你的业务数据,这就是个坑。
- 摘要:一句话交付:「
zipWith(f, as, bs)把函数 f 逐对作用于两个列表的对应元素,返回结果列表,长度等于较短的那个;多出的尾巴被丢弃。」
走查里没有任何编造的数——每一步产出都直接来自那段代码本身。七步走完,这段代码从「能看懂行」变成了「能向别人转述」,还顺手捞出一个作者都没写的潜在坑(第 6 步)。
7. 作者的判断与证据
**有实验撑着的:**脑区激活(西格蒙德,fMRI);能力预测(普拉特,36 人,三项成绩来源:课后测验、课程设计、考试);眼动(宇野的扫视研究、布贾恩的线性度对比,14 新手 6 老手)。三项研究的方法、被试、年代各不相同,但方向一致——这是本书里少有的多路证据合流。
作者的发挥,要分开看:「七策略照搬」是作者基于「认知相似性」做的系统性引申——七种策略本身来自文本阅读研究,搬到代码上的具体动作(比如打勾打问号的记号法)是作者设计的操作化,没有单独实验验证过有效性。
**书的坦白:**fMRI 有硬局限——被试必须躺着不动,没法测真实写代码,只能测读小段代码;这也是为什么还要靠脑电图、头带式的近红外设备补位(后者第 10 章还会出场)。
8. 边界与局限
- 普拉特研究的是初学者学 Python 的速度,不能直接推到「资深工程师的工程能力由语言能力决定」——度量的是入门期,不是精通期;
- fMRI 的样本与任务都高度简化(读短程序、躺平不动),「语言区激活」证明的是重叠,不是等同;
- 「学编程像学外语」的结论若推过头,会滑向「编程教学该照搬外语教学法」——书里没走这么远,读者也别替它走;
- 七策略是「读」的功夫;读完要不要信自己的理解,要靠第 08 章的测试与文档来兜底。
9. 可带走的
- 面试和自评别再拿「数学好不好」筛编 程潜质——语言能力是更好的预测项;
- 读陌生代码先扫一遍再细读,你的大脑本来就这么设计;
- 遇到陌生概念,先学概念再回来读代码,别边读边学;
- 求助时说「第几行到第几行没懂」,别说「这段没懂」;
- 看不出变量是什么类型时,看它被施加了什么操作——被调用的是函数,被取下标的是列表;
- 读完一段难代码,强制自己写一句自然语言摘要——写不出来就是没读完;
- 做摘要时顺手记录「作者的决策与代价」,那是文档里最值钱的部分。
10. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 布罗德曼分区与 fMRI | 5.4 阅读代码和阅读文本有相似之处 | text/33-ch05-04-5-4.txt:17(搜「布罗德曼」) · text/33-ch05-04-5-4.txt:21(搜「血流量」) |
| 西格蒙德实验 | 5.4 阅读代码和阅读文本有相似之处 | text/33-ch05-04-5-4.txt:25(搜「含义不明的变量名」) · text/33-ch05-04-5-4.txt:27(搜「5个布罗德曼分区」) · text/33-ch05-04-5-4.txt:29(搜「自然语言处理有关」) · text/33-ch05-04-5-4.txt:31(搜「混淆处理」) |
| 普拉特实验 | 5.4 阅读代码和阅读文本有相似之处 | text/33-ch05-04-5-4.txt:37(搜「36位学生」) · text/33-ch05-04-5-4.txt:41(搜「方差仅为2%」) · text/33-ch05-04-5-4.txt:45(搜「学习速度」) · text/33-ch05-04-5-4.txt:47(搜「取决于学习自然语言的能力」) |
| fMRI 的局限 | 5.4 阅读代码和阅读文本有相似之处 | text/33-ch05-04-5-4.txt:21(搜「不能移动」) |
| 眼动:扫视与线性度 | 5.4 阅读代码和阅读文本有相似之处 | text/33-ch05-04-5-4.txt:69(搜「30%的时间」) · text/33-ch05-04-5-4.txt:73(搜「75%的眼球运动」) · text/33-ch05-04-5-4.txt:73(搜「调用栈」) |
| 七种策略 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:7(搜「7种」) · text/34-ch05-05-5-5.txt:9(搜「激活」) |
| 激活:先学概念再读 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:29(搜「10分钟」) · text/34-ch05-05-5-5.txt:51(搜「加重认知负荷」) |
| 监测:勾与问号 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:57(搜「打对勾」) · text/34-ch05-05-5-5.txt:61(搜「更有效」) |
| 确定重要性 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:65(搜「25行重要的代码」) · text/34-ch05-05-5-5.txt:83(搜「相互交流的机会」) |
| 推断与标识符清单 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:89(搜「shipment」) · text/34-ch05-05-5-5.txt:95(搜「CustomerList」) |
| 操作表与 zipWith | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:127(搜「操作表」) · text/34-ch05-05-5-5.txt:131(搜「zipWith」) · text/34-ch05-05-5-5.txt:140(搜「列表或词典」) |
| 提问与摘要 | 5.5 运用文本理解策略来阅读代码 | text/34-ch05-05-5-5.txt:154(搜「最核心的5个概念」) · text/34-ch05-05-5-5.txt:174(搜「代码摘要」) |