Skip to content

《程序员超强大脑》

🏷️ 读书笔记

NOTE

点击查看 思维导图 版本

剖析程序设计之惑

  • 代码造成的各种困惑
    1. 缺乏知识
    2. 缺乏信息
    3. 缺乏加工能力
  • 影响程序设计的不同认知过程
    • 长时记忆
      • 长期保存获取的知识
    • 短时记忆
      • 暂时保存刚刚接收的信息
    • 工作记忆
      • 加工信息
      • 孕育新想法

快速阅读代码

  • 快速阅读代码
    • 程序员平均每天花在理解代码而不是编写代码方面的时间接近 60%。
      • 在保证准确的前提下加快代码阅读速度,对于提高编程水平大有裨益。
    • 代码是写给人看的,只是恰好能让机器运行。
    • 提高快速查找相关信息的能力有助于减少反复浏览代码的次数。
    • 不熟悉的标识符会增加快速查找、识别和记忆模式的难度。
    • 短时记忆
      • 留存时间很短
        • 不超过 30 秒,30 秒后必须进入长时记忆,否则将永远丢失。
      • 容量有限
        • 大约只能存储 2 ~ 6 个信息元素
  • 弥补记忆容量不足的短板
    • 为弥补容量不足的短板,短时记忆和长时记忆会协作记忆信息。
    • 组块(chunk)
      • 大脑会设法把接收到的新信息分解为可识别的元素(称为组块)
      • 大脑对某件事的印象越深刻,就越容易实现信息的有效分块。
      • 如果长时记忆没有存储足够的知识,那么大脑就不得不依靠字母和关键字等低层次的信息元素来阅读代码,从而很快耗尽短时记忆的容量。
      • 如果长时记忆存储的信息足够多,那么大脑就能记住抽象的概念(例如“Java 的 for 循环” 或 “Python 的选择排序”)而不是低层次的信息元素,从而减少短时记忆的占用。
    • 编程新手能够加工的代码比编程老手要少得多。
  • 看到的代码比读到的代码多
    • 进入短时记忆前,信息会经历成为感觉记忆(sensory memory)的阶段
    • 阅读代码时获得的信息首先进入图像记忆,只有少部分信息随后进入短时记忆。
    • 图像记忆
      • 阅读代码时,信息接收器官是眼睛,眼睛看到的信息会暂时存储于图像记忆。
      • 短时记忆并不会加工图像记忆存储的所有信息。
      • 阅读代码产生的大量信息进入大脑时,大脑必须在加工信息时做出取舍。换句话说,大脑在理论上可以记住超出短时记忆加工能力的信息。
      • 利用图像信息来提高代码阅读的效率:首先扫一眼代码,然后回忆刚刚看到的内容。
        • 扫视代码
    • 记忆方法
      • 记忆的顺序同样能帮助程序员理解代码
      • 编写易于分块的代码可以降低代码加工的难度
      • 使用设计模式有助于编写容易分块的代码
      • 程序员会花更多时间阅读包含注释的代码
      • 为代码添加注释有助于新成员更好地理解同事的代码库
      • 添加信标(beacon)也能使代码分块过程变得更容易
      • 信标类型
        • 简单信标
          • 自解释的语法代码元素,例如有意义的变量名。
        • 复合信标
          • 由多个简单信标构成的较大代码结构,为简单信标共同执行的功能提供语义。
        • 信标种类繁多,既可以是变量名和类名,也可以是其他标识符(例如方法名)。除了名称,特定的编码结构(例如交换或初始化为空列表)同样能够充当信标。
        • 与初级程序员相比,高级程序员在阅读和理解代码时会频繁使用信标。
    • 可以利用记忆代码来(自我)评估掌握的编程知识。大脑最容易记住已经知道的信息,因此在阅读代码时,能够记住的那些内容揭示了程序员最熟悉的设计模式、编程结构或领域概念。
    • 代码分块练习
      • 刻意练习(deliberate practice)
      • 积极尝试记忆代码是一种很好的手段

快速学习编程语法

  • 语法记忆小贴士
    • 大脑已经知道的信息会在很大程度上影响阅读代码和理解代码的效率。
    • 思路被打断所造成的影响或许远超想象。
      • 受到干扰的程序员往往需要大约一刻钟才能重新开始编写代码。
      • 一旦程序员将注意从正在编写的代码转向其它事情,就很容易忘记代码的重要信息。
    • 掌握的语法知识越多,代码分块越容易,因此务必熟记大量语法。此外,查找语法的用法会打断思路,从而影响工作效率。
  • 如何利用抽认卡快速学习语法
    • 无论学习语法还是其他知识,抽认卡都是加快学习速度的有效手段。
    • 抽认卡
      • 制作抽认卡时既可以使用纸质卡片,也可以使用便利贴。
      • 卡片一面写有文字提示(需要学习的内容),另一面写有相应的知识。
    • 抽认卡通常用于学习第二门语言且效果极佳。
    • 学习语法的诀窍在于使用抽认卡勤加练习。
    • 扩充抽认卡
      • 在学习新的编程语言、框架或库时,不妨为每次遇到的新概念制作一张抽认卡。
      • 对于不太常用的语法元素或概念,没有必要扩充抽认卡。
    • 精简抽认卡
      • 统计回答正确和错误的次数并记在卡片上,以评估自己对某个概念的熟悉程度。
  • 如何避免遗忘
    • 长时记忆只有经过反复练习才能实现信息的长期留存。
    • 长时记忆的衰退期不像短时记忆那样以秒为单位,但仍然比我们想象的短得多。
    • 大脑中的记忆不是按分层结构而是按网络结构来组织的。
      • 大脑在存储记忆的同时也会存储联想或记忆之间的关系。
    • 遗忘曲线
      • 赫尔曼·艾宾浩斯
    • 间隔重复
      • 学习的时间跨度越长,记忆的留存率越高。这并不代表需要增加学时,而是应该延长学期。
        • 长期来看,一个月复习一次抽认卡足以巩固记忆,这也是相对可行的一种策略。
  • 如何牢记编程语法
    • 不必在一天内记住所有抽认卡,而是应该延长学习的时间跨度。
    • 巩固记忆的方法
      • 提取练习(retrieval practive)
        • 主动回忆某些信息
        • 即使不记得完整的答案,经常回忆也更方便大脑检索记忆。
      • 精细加工(elaboration)
        • 主动将新知识与现有记忆联系起来
    • 记忆信息的两种机制
      • 存储强度(storage strength)
        • 表示信息在长时记忆中的存储情况
      • 提取强度(retrieval strength)
        • 表示记忆信息的难易程度
      • 学界普遍认为,存储强度只增不减,提取强度则会随着岁月的流逝而降低。
      • 提取练习
        • 在打开搜索引擎之前,建议程序员尽自己所能去记忆语法。即使这次记不住,尝试记忆的行为也可以巩固记忆,并为下次记忆奠定基础。
    • 精细加工
      • 运用精细加工策略来思考刚刚掌握的信息对于学习复杂的编程概念特别有效。
      • 图式
        • 图式(schema)描述了思维以及思维之间的关系在大脑中的组织方式。
        • 大脑首先设法把接收到的新信息构建为图式,然后存储到长时记忆。信息越符合现有的图式,大脑越容易记住它们。
        • 工作记忆在加工信息时也会从长时记忆检索相关的事实和记忆。如果记忆之间存在联系,那么检索起来就容易的多。换句话说,与其他记忆相关的记忆,其提取强度会更高。
        • 在存储记忆时,大脑甚至可以改变记忆使之适应现有的图式。
          • 大脑不是单纯的去记忆单词和事实,而是根据已有的记忆和信仰调整需要记忆的内容。
      • 精细加工可用于强化记忆的初始编码:主动思考希望记住的内容,并把这些内容与已有的记忆联系起来,同时引导新的记忆融入长时记忆已经存储的图式。

阅读复杂的代码

  • 为什么复杂的代码难以理解
    • 工作记忆一次只能加工 2 ~ 6 个信息元素,这种能力称为认知负荷(cognitive load)。当大脑尝试解决某个涉及太多信息元素且无法有效分块的问题时,工作记忆就会出现“过载”情况。
      • 内部认知负荷
        • 源于问题本身的复杂性
      • 外部认知负荷
        • 外部因素对问题的影响(与代码的表现形式有关)
      • 关联认知负荷
        • 思维形成长时记忆时所产生的认知负荷
  • 减轻认知负荷的方法
    • 重构(refactoring)
      • 通过调整代码来改进其内部结构,但不改变代码的外部行为。
      • 然而,整体共容易维护的代码未必更容易阅读。
    • 认知重构(cognitive refactoring)
      • 同样是对代码库进行调整而不改变其外部行为,但目的不是使代码更容易维护,而是方便程序员在现阶段阅读和理解。
      • 认知重构有时会设计反向重构,这种重构会降低可维护性。
    • 替换不熟悉的语言结构
      • lambda 表达式
      • 列表推导式
      • 三元运算符
  • 利用记忆辅助工具解决工作记忆过载的问题
    • 绘制依赖图(dependency graph)
      • 主要用于判断代码的组织方式
    • 创建状态表(state table)
      • 主要用于判断代码执行的计算

深入理解代码

  • 变量角色框架
    • 变量角色
      • 固定值 fixed-value
      • 步进器 stepper
      • 标志 flag
      • 步行器 walker
      • 最近持有器 most-recent-holder
      • 最佳持有器 most-wanted-holder
      • 收集器 gatherer
      • 容器 container
      • 跟随器 follower
      • 组织器 organizer
      • 临时 temporary
  • 角色和范式
    • 角色并不局限于特定的编程范式,而是适用于所有范式。
    • 匈牙利命名法 Hungarian notation
      • 系统性匈牙利命名法
      • 应用型匈牙利命名法
  • 加深对程序的了解
    • 文本结构知识 text structure knowledge
      • 代表对程序的表面理解
    • 计划知识 plan knowledge
      • 代表理解代码编写者在开发程序时计划实现的目标
  • 阅读代码和阅读文本的相似之处
    • 布罗德曼分区 Brodmann area
      • 描述大脑各个分区的主要功能
    • 与工作记忆和语言处理有关的大脑区域会参与编程活动。
  • 运用文本理解策略来阅读代码
    • 阅读代码和阅读自然语言所用的认知技能很接近
    • 阅读理解策略
      • 激活:主动思考相关信息以激活先验知识
      • 监测:随时掌握理解文本的情况
      • 确定重要性:判断哪部分文本的相关性最高
      • 推断:补全文本中没有明确给出的事实
      • 视觉化:通过绘制文本的图表以加深理解
      • 提问:针对当前的文本提出问题
      • 摘要:编写简短的文本摘要

更好地解决编程问题

  • 借助模型来思考代码
    • 模型是对显示的简化表征
    • 模型有助于团队成员相互交流程序的相关信息
    • 模型有助于解决问题
      • 构建模型是减轻认知负荷的有效方法
    • 模型有助于长时记忆检索相关记忆
  • 心智模型 mental modal
    • 心智模型时大脑在思考问题时形成的心智表征
    • 心智模型在工作记忆中创造出某种抽象,可以用来推理当前的问题
    • 重要特征
      • 心智模型是不完整的
      • 心智模型是不稳定的
      • 相互矛盾的多个心智模型可以共存
      • 心智模型可能很“诡异”,甚至使人产生迷信的感觉
      • 人们在迫不得已时才考虑使用心智模型
    • 学习新的心智模型
      • 学习编程的过程往往是逐步掌握新模型的过程
      • 多个心智模型可以同时处于活跃状态,这些模型并非总是泾渭分明
      • 程序员可能会依靠简单的心智模型来阅读复杂的代码
      • 构建代码的抽象模型是提高代码分析效率的有效手段之一,因为程序员可以从模型本身入手推理代码的作用,而不必依赖观察代码这种效率低下的方式。
      • 构建准确而具体的心智模型有助于分析复杂的系统。
      • 构建复杂代码心智模型的步骤
        • 从构建局部模型入手
        • 列出代码库中所有相关对象以及对象之间的关系
        • 回答系统的相关问题,并根据答案来完善模型
      • 在阅读复杂的源代码时,重点不是构建具体的心智模型,而是掌握更多的心智模型。
      • 长时记忆存储的心智模型会影响工作记忆构建的心智模型
  • 概念机器 notional machine
    • 首先,概念机器代表一种可以随时与之交互的机器,与为某种事物构建的心智模型有很大不同。
    • 其次,构成“概念机器”一词的另一个元素是概念,《牛津英语词典》的释义是“作为或者基于某种建议、估计或理论而存在,现实中不存在”。
  • 概念机器和语言描述
    • 不要贸然采用现实生活中的对象和操作来描述编程概念和计算机相应的工作原理。
  • 概念机器和图式
    • 逻辑清晰的概念机器将编程概念与大脑中业已形成有效图式的日常概念联系在一起。
    • 图式描述了长时记忆存储信息的方式。
    • 在解释某个概念时务必选择对方熟悉的类比。

迷思概念:错误的思维方式

  • 为什么学习第二门编程语言比学习第一门编程语言更容易
    • 长时记忆存储的信息能够促进新知识的学习,这种情况称为学习中迁移(transfer during learning)
    • 长时记忆存储的知识还能通过学习迁移(transfer of learning)起到促进作用
    • 影响迁移量的因素
      • 掌握:针对任务的熟悉程度,完成任务所需的知识已经存储在长时记忆中。越了解一项任务,就越有可能将其应用到其他领域。
      • 相似性:两项任务之间的共同点。
      • 情境:环境的相似程度。
      • 关键属性:在多大程度上了解可能从哪些知识中获益。
      • 联想:在多大程度上感受到任务之间的相似程度。
      • 情绪:对任务的感觉。
    • 不同的迁移类型
      • 低阶迁移(low-road transfer):无意识地将已经掌握的技能应用于新情境。
      • 高阶迁移(high-road transfer):有意识地将已经掌握的技能应用于新情境。
      • 近迁移(near transfer):将已经掌握的知识应用于相似的领域。
      • 远迁移(far transfer):将已经掌握的知识应用于差异较大的领域。
      • 正迁移(positive transfer):已掌握的知识对学习新知识起到促进作用。
      • 负迁移(negative transfer):已掌握的知识对学习新知识起到阻碍作用。
    • 迁移确实有难度,而且大多数情况下不会自动产生
    • 有意识地注意两门语言的异同可以降低学习新语言的难度
  • 迷思概念:思维中存在的错误
    • 某种认知只有满足以下条件才属于迷思概念
      • 不正确
      • 在不同的情况下始终存在
      • 使人坚信不疑
    • 为新语言构建正确的心智模型并用它来取代原有语言的迷思概念称为概念转变(conceptual change)
    • 就算能成功运用正确的概念解决问题,人们还是会经常依靠原先的概念
    • 科学家虽然不清楚大脑究竟如何决定使用哪种已有的概念,但认为抑制在决策过程中会起到一定作用
    • 在学习新的编程语言时避免形成迷思概念
      • 首先,应该明白,即使充分相信自己的水平,也不能保证自己的判断就一定正确,所以做到心态开放、不报成见很重要。
      • 其次,建议程序员有意识地研究常见的迷思概念以少走弯路。
      • 最后,如果能找到按照相同顺序学习同一门编程语言的程序员,那么不妨听听他们的建议。
    • 结对编程或小组编程是排除迷思概念的手段之一
    • 文档是避免迷思概念的另一种手段

提高命名的质量

  • 命名为什么重要
    • 构思一个优雅的标识符相当困难。用一个含义明确的单词来完整概括某个类或数据结构的作用并不容易。
    • 虽然取名很难,但为所推理的对象选择合适的名称很重要。
    • 命名的重要性
      • 标识符是代码库的重要组成部分
      • 标识符在代码审查中起到一定作用
      • 标识符是最常见的文档类型
      • 标识符可以充当信标
    • 与标识符有关的不同观点
      • 标识符应该遵循语法规则
      • 标识符在代码库中应保持一致
    • 最初的命名实践影响深远
      • 标识符质量在程序开发的早期阶段就已定型
      • 命名实践的变化趋势
        • 如今的代码更遵循命名实践
        • 但是在同一个代码库内,命名实践保持不变
        • 代码库的规模不会影响命名实践
  • 从认知的角度剖析命名
    • 规范的命名方式对短时记忆有利
    • 含义明确的标识符对长时记忆有利
    • 标识符可以包括不同类型的信息以帮助理解
      • 领域知识
      • 编程概念
      • 命名约定
    • 设计标识符时,强烈建议把是否方便今后阅读纳入考虑,以有利于短时记忆和长时记忆为准绳。
  • 哪些类型的标识符更容易理解
    • 是否应该使用缩写
      • 由完整单词构成的标识符比由缩写或单字构成的标识符更容易理解。
      • 标识符越长,所含的音节数量越多,记忆难度就越大。
    • 采用驼峰命名法还是蛇形命名法
      • 如果不考虑其他区别,那么程序员更容易记住采用驼峰命名法的变量,但能够更快找出采用蛇形命名法的变量。
  • 标识符与代码错误之间的关系
    • 低质量的标识符会引发更多代码错误
      • 但不意味着两者必然存在因果关系
    • 标识符质量越高,理解代码就越容易,因此改进标识符可以在一定程度上减少错误,至少能够缩短修复错误的时间。
  • 如何设计质量更高的标识符
    • 命名模具 name mold
      • 命名模具旨在描述各个元素组合成变量名的典型方式。
      • 首先,在变量名和构成变量名的不同元素中检索相关概念会增加不必要、不相干的认知负荷。
      • 其次,如果变量名相似,那么使用相同的模具也许更便于长时记忆检索相关信息。
        • 每个代码库最好不要使用太多不同的模具
    • 三步模型
      1. 选择标识符要体现的概念
        • 思考标识符包含哪些概念也许是命名中最重要的决定
      2. 挑选代表每个概念的单词
        • 为了提高命名的一致性,可以考虑建立项目词库(project lexicon)
      3. 根据这些单词设计标识符
        • 本质上是选择一个名称模具

避免低质量代码和认知负荷:两种框架

  • 为什么存在异味的代码会加重认知负荷
    • 有异味不一定说明代码存在错误,但有异味的代码往往更容易出错。
    • 代码异味对认知的负面影响
      • 导致工作记忆过载的异味:过长的参数列表和复杂的 switch 语句
      • 阻碍有效分块的异味:过大的类和过长的方法
      • 导致分块错误的异味:重复的代码
  • 低质量标识符对认知负荷的影响
    • 语言反模式
      • 代码的语言元素与其角色不符
    • 尽管可以凭直觉猜测标识符的含义,但语言反模式可能造成困惑,从而加重认知负荷。
    • 代码中存在的语言反模式越多,所产生的认知负荷就越大。
    • 语言反模式之所令人感到困惑,还有一个原因是它们可能引发类似于代码克隆的“分块错误”。

提高解决复杂问题的能力

  • 问题解决的实质
    • 问题解决的三大要素
      • 目标状态(希望实现的目标)
      • 待解决问题的起始状态
      • 描述如何从起始状态达到目标状态的规则
    • 状态空间
      • 解决问题时,所有可以实施的步骤称为问题的状态空间
      • 问题解决的实质是以最优方式遍历状态空间,争取用最少的步骤达到目标状态
  • 长时记忆在解决编程问题时所起的作用
    • 问题解决设计长时记忆
    • 对大脑来说,解决熟悉的问题更容易
    • 长时记忆
      • 程序性记忆(内隐记忆):关于运动技能或无意识技能的记忆
      • 陈述性记忆(外显记忆):能够有意识地回想起某些事实地记忆
        • 情景记忆:个人经历
        • 语义记忆:意义、概念或事实的记忆
    • 所有长时记忆都会影响编程活动。外显记忆可能是编写代码时首先用到的记忆,但其他类型的记忆也会起到一定作用。
    • 情景记忆在回忆之前解决问题的方法时会派上用场。从某种意义上将,资深程序员是在重现而非解决熟悉的问题。
    • 忘却学习
      • 内隐记忆有助于快速解决熟悉的问题,但这种记忆未必多多益善。
      • 如果程序员曾经学过语法与第一门编程语言截然不同的第二门语言,那么或许也能体会到忘却内隐记忆的不易。
  • 自动化:构建内隐记忆
    • 一旦某项技能经过反复练习后成为本能,就可以认为这项技能已经实现自动化。
    • 与程序设计有关的内隐记忆越丰富,大脑承受的认知负荷就越少,解决更复杂的问题时也越轻松。
    • 内隐记忆主要通过重复的方式产生。
    • 内隐记忆的形成分为 3 个阶段
      • 认知阶段:大脑不仅要把接收到的新信息分解为较小的元素,而且必须有意识地思考如何完成当前的任务。
      • 联想阶段:大脑需要主动重复新信息,直到形成反应模式。
        • 任务或事实越困难,联想阶段持续的时间就越长;任务或事实越简单,记忆所需的时间就越短。
      • 自主阶段:技能在这一阶段得到完善。
        • 一旦达到自主阶段,就可以认为技能已经实现自动化。
    • 实现自动化的标志是大脑完全依靠情景记忆而不是推理来完成任务。
    • 强化内隐记忆
      • 首先,程序员不妨针对需要巩固的技能编写大量相似但不同的程序。
      • 其次,如果程序员疲于应付更复杂的编程概念,那么也可以考虑修改程序而不是从零开始编写程序。
      • 学习的诀窍在于使用抽认卡勤加练习。
  • 从代码及其解释中汲取经验
    • 提高问题解决能力的第二种方法是认真研究其他人的解决方案,也就是通常所说的样例。
    • 第三种认知负荷:关联认知负荷
      • 关联认知负荷与图式构建和自动化有关,用于描述大脑将信息转化为长时记忆而付出的努力。如果内部认知负荷和外部认知负荷增加,那么关联认知负荷就会减轻,导致大脑很难记住曾经解决的问题及其解决方案。
    • 在工作中运用样例
      • 与同事合作
        • 首先,程序员不必单打独斗,与其他人一起研究代码的效果更好。
      • 用好 GitHub
        • 强烈建议从 GitHub 入手阅读代码。挑选一个有所了解的仓库(例如自己使用的库),然后阅读其中的代码即可。
      • 阅读探讨源代码的图书或博文
        • 许多博文记录了程序员解决某个变成问题的方法,这些博文同样可以作为研究代码的资料。

编程活动和任务

  • 程序设计包括不同的编程活动
    • 符号认知维度框架旨在评估编程语言或代码库的认知影响,这种框架将程序设计分为 5 种编程活动
      • 搜索:在代码库中查找特定信息的活动
      • 理解:理解活动涉及阅读代码和执行代码以了解其功能
      • 转写:转写活动大体围绕写代码进行
      • 递增:递增是搜索、理解和转写的结合。
      • 探索:从本质上将,探索活动是运用代码来勾画问题的轮廓。
  • 收到干扰的程序员
    • 数据显示,程序员经常受到干扰,每次持续 15 ~ 20 分钟。
    • 数据显示,程序员平均每天只有两小时能排除干扰、专心工作。
    • 程序理解进行到一半时其认知负荷最高。
    • 程序理解任务中或许存在某种预热期和冷却期,最难的工作在两个阶段之间进行。专业程序员可能需要这段预热期来“进入状态”,以便构建代码的心智模型并为转写活动做好准备。
    • 打断正在工作的程序员会导致工作记忆丢失代码的重要信息。
    • 如何减轻干扰的影响
      • 保存心智模型
        • 把决策记录在案不仅能极大方便其他代码阅读者,而且有助于代码编写者暂时保存自己构建的心智模型,从而为后续编程提供便利。
        • 如果遇到思路被打断但可以暂时忽略干扰的情况,那么将自己为代码构建的最新心智模型全部写进注释可能有很大帮助。
      • 改善前瞻性记忆
        • 前瞻性记忆:一种关系到将来而不是过去的记忆。
        • 待办事项注释:TODO
        • 便条或邮件
      • 标记子目标
        • 明确写下可以把问题分解为哪些小步骤。
    • 限制干扰出现的时机
      • 如果思路被打断在所难免,那么把干扰限制在功能合适的时候发生或许有助于减轻其负面影响。
    • 关于多任务处理的一些思考
      • 大量数据表明,人们无法在认知负荷较高时做到一心多用。
      • 有趣的是,一心多用的学生往往会觉得自己的效率很高。

设计和改进大型系统

  • 代码库的属性
    • 认知维度 cognitive dimensions
      1. 易错性
        • 采用某些语言进行编程比其他语言更容易出错。
      2. 一致性
      3. 扩散性
        • 描述编程结构占用的空间。
      4. 隐藏的依赖关系
        • 描述依赖关系对用户的可见程度。
      5. 临时性
        • 描述使用工具时思考的难易程度。
      6. 黏性 viscosity
        • 描述修改给定系统的难易程度。
      7. 渐进式评估
        • 描述在给定系统中检查或执行部分代码的难易程度。
      8. 角色可表达性
        • 描述查询程序中不同代码元素所起的作用的难易程度。
      9. 映射紧密型
        • 描述编程语言或代码库与待解决问题的领域的接近程度。
      10. 艰难的心理操作
        • 某些系统会显著增加大脑的负担,用户需要在系统外部执行艰难的心理操作(hard mental operation)。
        • 艰难的心理操作也不全是坏事,用户做所的思考可能会得到回报。
      11. 辅助符号
        • 描述程序员为代码添加的额外信息,这些信息不属于形式规约。
        • 源代码的注释就是最常见的辅助符号。
      12. 抽象
        • 描述系统用户能否创建与内置抽象一样强大的抽象。
      13. 可见性
        • 描述查看系统不同部分的难易程度。
    • 符号认知维度旨在评估现有大型代码库的可用性。
    • 为改进代码库的某个维度而做出的调整称为设计策略(design maneuver)
    • 一般来说,应用一项设计策略(针对一个维度的调整)会导致另一个维度发生变化。维度之间相互影响的确切方式与代码库密切相关,但是有几个维度往往存在此消彼长的俄关系。
      • 易错性和黏性
      • 临时性和渐进式评估与易错性
      • 角色可表达性与扩散性
  • 认知维度和编程活动
    • 以符号认知维度框架描述的认知维度为准绳,可以通过设计策略来改进现有代码库的设计。
    • 不同的编程活动对代码库优化的认知维度提出了不同的要求。

对程序员进行适岗培训

  • 适岗培训中存在的问题
    1. 资深程序员向新成员抛出大量新信息,导致他们被信息的洪流淹没,大脑承受了很高的认知负荷。
    2. 介绍完毕后,资深程序员向新成员提出一个问题或交给他们一项任务。资深程序员往往认为,诸如修复一个小问题或添加一项小功能这样的任务应该是举手之劳。
    3. 新成员既缺乏相关领域或编程语言进行分块的能力,也没有实现相关技能的自动化,以致大脑承受的认知负荷较高,无法完成培训者交给自己的任务。
  • 高级程序员和初级程序员的区别
    • 高级程序员的思维方式有哪些不同
      1. 高级程序员的大脑中存储着大量相关记忆,工作记忆可以从长时记忆中提取出这些信息,包括经过刻意学习的策略或关于个人经历的情景记忆。
      2. 高级程序员具备极强的代码分块能力,对错误消息、测试、问题、解决方案等代码相邻工件进行分块同样不在话下。
    • 皮亚杰理论
      • 把儿童的认知发展分为 4 个阶段
        • 感觉运动阶段:儿童缺乏制定方案或策略的能力,仅靠感觉和知觉来认识世界(0 ~ 2 岁)
        • 前运算阶段:儿童开始具备做出假设和制定方案的能力,但无法稳定可靠地运用这些能力进行思考(2 ~ 7 岁)
        • 具体运算阶段:儿童有能力对观察到的具体事务进行推理,但很难得出一般性结论(7 ~ 11 岁)
        • 形式运算阶段:儿童开始具备形式推理能力(11 岁以上)
    • 新皮亚杰理论
      • 认知发展具备领域特殊性而不是领域普遍性。
      • 新皮亚杰理论提出的认知发展阶段以及相应的编程行为
        • 感觉运动阶段:程序员对程序执行的理解不成体系,不具备正确跟踪程序的能力
        • 前运算阶段:通过状态表等方式,程序员能够稳定可靠地预测多行代码地输出结果,他们经常会尝试猜测一段代码地作用
        • 具体运算阶段:程序员通过阅读代码本身而不是采用前运算归纳法对代码进行演绎推理
        • 形式运算阶段:程序员开始具备进行逻辑性推理、一致性推理和系统性推理地能力;形式运算推理包括思考自己地行为,这一点对于调试直观重要。
      • 在学习信息时,中级程序员的思维有时会“退化”到初级程序员的水平。
      • 高级程序员往往采用非常笼统和抽象地术语,从不同地角度讨论某个概念。
      • 语义波理论:学习者先根据具体的细节将抽象的知识解包,再将学到的知识重新打包并存储到长时记忆中
        • 学习者首先需要从宏观角度认识某个概念,包括了解它的用途以及掌握这个概念的重要性。
        • 在了解概念的大致用途后,语义轮廓从波峰转向波谷,这个过程称为解包(unpacking)。
        • 最后,学习者需要对概念进行抽象概括,这个过程称为重新打包(repacking)。重新打包还包括将刚掌握的知识和先验经验合并存储到长时记忆中。
  • 完善适岗培训流程
    • 对培训者来说,有意识地管理受训者的认知负荷是第一要务;对受训者来说,能够管理自己的认知负荷无疑也有很大帮助。
    • 适岗培训期间,一次只安排受训者执行一项编程活动。
    • 适岗培训开始前,请准备好有助于改善受训者的长时记忆、短时记忆和工作记忆的相关资料。
    • 培训者首先应该明白,自己觉得容易掌握的知识,受训者未必觉得容易。
      1. 解释相关信息以改善长时记忆
        • 培训者不妨把代码中所有重要的领域概念都整理出来供受训者参考。
        • 代码中出现的所有库、框架、数据库以及其他外部工具同样可以作为相关信息。
        • 即使不是针对适岗培训,也建议把项目涉及的所有领域概念和编程概念整理出来并随时调整,团队目前的程序员可能会因此受益。
      2. 安排有针对性地小任务以改善短时记忆
      3. 使用图表以改善工作记忆
    • 团队成员一起阅读代码也是培训新人的一种手段
      • 团队一起阅读代码能够减轻新成员地认知负荷,从而为工作记忆加工代码留出更多空间。
      • 文本阅读策略同样适用于代码阅读
        • 激活:共读环节开始前,请盘点代码中涉及地相关概念。
        • 确定重要性:假如对某个领域知之甚少,就很难区分哪些是核心知识,哪些是次要知识。如果新成员了解相关性最高地代码,则有助于他们熟悉项目。
        • 推断:补全没有明确声明地细节同样很困难。
        • 监测:培训者在适岗培训期间最重要地任务是随时掌握受训者的理解水平。
        • 视觉化:根据受训者的水平,培训者既可以自己绘制图表以帮助他们阅读代码,也可以要求受训者绘制图表以加深对代码的理解。
        • 提问:代码共读应该纳入定期问答环节。根据受训者的水平,既可以采用“我问你答”的形式,也可以采用“你问我答”的形式。
        • 摘要:在适岗培训期间,代码共读的最后一步是为一起读过的代码编写摘要。根据代码库的文档状态,可以在共读环节结束后将摘要作为文档提交到代码库。