《程序员超强大脑》读书笔记
整理一些对自己有启发和帮助的点,与君共享,强烈推荐这本书,值得从新手到中高级程序员共读
文章目录
记忆
工作中,经常有些大佬,你问他项目的很多细节,都能给你一一道来,难道他们的记忆就那么厉害吗?
自己也试过记笔记,为啥没啥效果,而且很多事情,时间长了,啥都想不起来了,领导问的时候很尴尬,必须借助confluence文档或自己的笔记才能复现。
为什么会出现这种情况?我们的大脑到底是怎么记忆的?
大脑有三种记忆方式:
长时记忆
长时记忆(long-term memory) 可以无限期存储所有记忆,比如你走路的时候肯定不会想着怎么走,甚至同时还能打电话、聊天;有些人写二叉搜索树很快,这些都属于长时记忆。类比硬盘。
长时记忆会存储几类相关的编程信息,例如成功运用某种编程技巧的记忆、Java关键字的含义、英语单词的含义或者Java中int型变量的最大值(2147483647)。
短时记忆
短时记忆,它用于暂时保存大脑接收的信息。比如你收到验证码短信,不会进入长时记忆。类比内存。
在阅读程序时,大脑会把程序使用的关键字、变量名和数据结构暂时保存在短时记忆中。
进入短时记忆之前,信息会经历感觉记忆(sensory memory)的阶段。类比于鼠标、键盘等输入设备相互通信的I/O缓冲区。感觉记忆用于暂时存储大脑接收的视觉、听觉或触觉信息。
与视觉信息有关的感觉记忆,即图像记忆(iconic memory)。类比翻页书,闭上眼睛仍能“看见”图像。
利用图像记忆来提高代码阅读的效率:首先扫一眼代码,然后回忆看到的内容。练习“扫视代码”有助于大脑建立起对代码的初步印象。
工作记忆
实际的思维活动不是在短时记忆或长时记忆中进行,而是在工作记忆中进行。大脑内部用于追踪以及进行其他复杂认知活动的机制称为工作记忆。工作记忆是孕育新想法、新观点以及新方案的摇篮。相当于大脑的“处理器”。
在阅读代码的过程中,大脑尝试在脑海里组织并执行代码。如果大脑感觉需要借助外部媒介来存储信息,则可能意味着工作记忆的负担过重,难以加工更多信息。
那如何利用这些理论呢?
使用设计模式
其实跟我们汉语的成语一样,能让别人快速识别自己的代码
编写注释
有助于新成员更好地理解同事的代码库,此外,不是一开始就能写出完整的代码,写代码时也有可能被打断思路(比如开会、电话、微信等),有注释能让我们更快的回忆,进入状态。
添加信标
beacon,包含简单信标和复合信标。
简单信标:简单信标是自解释的语法代码元素,例如有意义的变量名。比如root、tree、&&、if等
复合信标:由多个简单信标构成的较大代码结构。例如,for循环包括变量、初始化赋值、增量值以及边界值,特定的编程结构(例如交换或初始化为空列表)同样能够充当信标。
在阅读代码时,多关注信标,注释、变量名、方法名或中间值,它们都能充当信标。
抽认卡
抽认卡的目的,是让概念从短时记忆存储到长时记忆。
形式可以是纸质的,也可以是电子版,如开源的anki。
内容可以是编程语言、框架、代码片段。比如正面:执行某种计算的推导式;反面:[x * x for x in numbers]
。
流程:整理抽认卡 --> 使用(练习,可敲键盘再对比) --> 扩充抽认卡 --> 精简抽认卡
主动记忆
存储到长时记忆很重要,但更重要的是工作记忆要能很快提取。如何做到?和生活中很多事情一样,经常练习也就是主动记忆才能巩固记忆。
如何主动记忆?在谷歌之前先设法记住信息。
减轻认知负荷
代码重构
为什么要重构代码,因为代码太乱,在阅读代码时让我们的工作记忆不堪重负,因此需要认知重构(cognitive refactoring),帮助我们读懂代码,如将方法声明移到第一次方法调用附近或许有助于提高代码可读性。又比如三元运算符、lamda表达式等的重构。由于程序员先验知识并不一样,认知重构因人而异,其目的只是帮助程序员理解代码,属于临时操作,有git之后,可以自建分支用来梳理代码。
依赖图
复杂的代码,需要使用依赖图。依赖图(dependency graph)不仅有助于理解代码流,而且有助于遵循逻辑流程来阅读代码。如何绘制?打印为pdf,不要用IDE进行跳转,然后梳理变量、方法、类等,不同颜色圈中、连线,查看。
状态表
过于复杂的,可能需要状态表,比如工作流,记录每个变量的初始值、每一步之后的值,减轻认知负荷。
代码深层含义
变量角色框架
变量在代码推理中处于主导地位,含义明确的变量名,对理解代码至关重要。为什么变量难以理解?因为程序员没有专业训练和语言规范,长时记忆没有建立起能够关联变量的有效图式。
东芬兰大学教授Jorma Sajaniemi设计变量角色框架(roles of variables framework)描述了变量在程序中承担的任务。11种角色描述大多数变量:
- 固定值(fixed-value):如果变量的值在初始化操作后不会发生变化,那么变量的角色就是固定值。可以是常量如final修饰的关键字、可以是赋值一次后值不再改变的变量、也可以是从文件或数据库读取的数据。
- 步进器(stepper):在循环中进行迭代时,总会有一个变量负责遍历值列表,也就是步进器。步进器变量既可以很简单(例如for循环的标准计数器变量i),也可以很复杂(例如二分搜索的数组长度size = size / 2,其中每次迭代时数组长度都会减半)。
- 标志(flag):如果变量用于指示程序执行情况,那么它的角色就是标志。比如isXxx。这种变量通常是布尔值,但也可以是整数甚至字符串。
- 步行器(walker):和步进器变量的作用都是遍历数据结构,步行器变量的遍历方式在循环开始前无法预测。多数情况用于遍历栈或树等数据结构。遍历某个链表以查找新元素插入位置的变量是步行器变量,二叉树的搜索索引同样是步行器变量。
- 最近持有器(most-recent-holder):在遍历值列表的过程中,如果变量用于保存最新的一个值,那么它的角色就是最近持有器。既可以存储从文件中读取的最新一行代码(line = file.readline()),也可以存储步进器变量最后引用的数组元素的副本(
element = list[i]
)。 - 最佳持有器(most-wanted-holder):遍历值列表的目的往往是为了查找某个值。如果变量用于保存最精确或目前为止最接近的搜索结果,那么它的角色就是最佳持有器。既可以存储最小值或最大值,也可以存储满足特定条件的第一个值。
- 收集器(gatherer):如果变量用于收集数据并聚合为一个值,那么它的角色就是收集器。比如累加的sum。
- 容器(container):这种数据结构用于存储多个可以添加或删除的元素,列表、数组、栈或树都属于容器。
- 跟随器(follower):某些变量的当前值总是依赖于其他变量的前一个值。这种变量的角色是跟随器,它始终与另一个变量相互关联。例如,跟随器变量既可以是遍历链表时指向表中前一个元素的指针,也可以是二分搜索中的下标。
- 组织器(organizer):有时候,变量在进一步处理前必须先转换为某种形式。比如可能希望对给定的列表进行排序后再存储。组织器变量的作用仅仅是以不同方式重新排列或存储值,这种变量往往属于临时变量。
- 临时(temporary):临时变量的值只在短时间内使用,比如交换数据。
![[Pasted image 20231209170352.png]]
构建代码的心智模型
工作记忆的心智模型
- 从构建局部模型入手。
- 列出代码库中所有相关对象以及对象之间的关系,先用白板或数字化工具列出代码中出现的元素,再标出元素之间的关系,以弄清不同元素之间的相互作用,从而加深对整个系统的了解。
- 回答系统的相关问题,并根据答案来完善模型,如下
a.系统中最重要的元素(类、对象、页面等)是什么?心智模型是否包括这些元素?
b.这些重要的元素之间有哪些关系?
c.程序的主要目标是什么?
d.这些目标与核心元素之间有哪些关系?
e.能否给出一个典型的用例?心智模型是否涵盖这个用例?
长时记忆中构建代码的心智模型
一种方法是使用抽认卡。卡片一面写有心智模型的名称(提示),另一面写有心智模型的简要解释或图示。通常会考虑以下因素:
- 数据结构(例如有向图、无向图、不同形式的列表等);
- 设计模式(例如观察者模式);
- 架构模式(例如MVC模式);
- 图(例如实体关系图或时序图);
- 建模工具(例如状态表或佩特里网)
每次遇到陌生的模式时,都可以考虑制作一张新的抽认卡。
二是帮助自己理解晦涩难懂的代码:逐一浏览心智模型的抽认卡,并判断是否适用于当前的代码。
例如,挑选一张树结构的抽认卡问问自己:“这段代码能否用树结构来描述?”如果答案是肯定的,那么可以根据这张卡片着手构建初步的模型,也就是确定模型包括哪些节点、叶、边以及这些元素可能的含义。
变量名 三步模型
第1步是选择标识符要体现的概念
某些情况下,在标识符中加入类型指示信息同样很重要,例如标明长度类型(水平长度还是垂直长度)、重量单位(千克还是磅)或缓冲区包含用户输入(因此存在安全隐患)
第2步是挑选代表每个概念的单词。可以考虑建立项目词库(project lexicon),把所有重要的定义记录在案,并给出同义词的替换词。
第3步是根据选定的单词来设计标识符,本质上是选择一个名称模具。选择与代码库保持一致的模具很重要。
提高解决复杂问题的能力
第一种方法称为自动化(automatization),也就是能够不假思索地完成小任务。
第二种方法是借鉴其他人所写的代码并化为己用,以提高自己的问题解决能力。
第二种的目前有很多参考书籍,比如
- 项目库 项目有很多需求分析、设计
- github 比较厉害的开源项目
- 阅读探讨源代码的图书或博文 The Architecture of Open Source Applications和500 Lines or Less,现在也有很多java相关的书,比如 《从程序员到架构师》