建议,捷径,对原有方法的修改
在过去的几年里,我就使用间隔重复抽认卡来加速编程学习大作了一番讨论。但我意识到太新颖的想法难以评估其功用,所以这篇文章的目的,是在我早期的热情之作的基础上,在又一年日日不间断的卡片复习之后,进一步优化我的方法论。
为了给我和读者节省时间,我已经把内容浓缩成论点的形式。每个小节代表了我的学习策略中加入的一个原则,其指导方针是在最短的时间内学习尽可能多的材料。
1. 截图卡片优于纯文本卡片
我最早的方法是将纯文本代码片段粘贴到我的牌组里。而我现在都是把代码示例截图(利用快捷键),这些代码有的是我在文本编辑器中打开的、有的来自编程书籍,有的来自诸如 Stack Overflow 之类的网站。我不需要在 Anki 中再次键入代码,便节省了时间。我还能顺带获得语法高亮显示,于是我阅读卡片更快了,复习速度也有提升。
请允许我插嘴说一说非严格的 Tim Ferris 风格的的科学直觉:我认为把事实做成卡片后,在卡片中用图像记录事实的来源,是有助于记忆卡片的,因为
i) 基于位置的记忆比其他种类的记忆更强;
ii) 颜色、字体和网站 URL 形成的记忆,比全是文本的卡片更丰富、更独特,因此更容易被记忆。
2. 关注可用功能而不是细节
最初,我将每个函数的详细信息放入我的牌组中,包括类名、返回值及其类型、参数列表和参数顺序。这些年来,我发现一旦加上其他编程语言一起学习,这些信息就很难记住了,尤其是函数名称相似,但用法略有不同的时候 (例如 each())。编程语言之间跳转的过程中,我意识到,这种详细的信息仅能短期提升速度,但很快就失效了。尽管如此,我很高兴我有一门“母语”语言 (对我来说是Ruby) 我是熟悉到掌握了大量细节的,因为这意味着我可以快速地写出个人实用软件、顺手的工具和脚本。
更重要的是要记住哪些内置函数是语言提供的,以及哪些服务在操作系统或协议中存在的。我为各种 Linux 命令或有用的 Javascript 内置窗口属性创建卡片。
有时我会制作「混合卡」——这是我自创的术语。这种卡片总结了某个命令是什么,也囊括了操作中的细节。为此,我在卡片背面先回答「它是什么」,再跟上深入的描述或者实际使用中的代码 (包含真实参数与输出),就像语言学习者为新词汇提供例句一样。我复习时可以瞟一眼这个函数的真实用例,但我并不尝试去背下它。如果之后我恰好有项目需要卡片中描述的特性,我把这些卡片单拎出来 (利用 Anki 的强记模式),并学习卡片上更细节的信息。
3. 剪贴簿卡片
平面设计师有制作剪贴簿的习惯,在剪贴簿中保存他们欣赏的艺术作品和设计,未来的项目需要寻找灵感时可供参考。程序员也可以效仿。一看到特别优雅、高效或聪明的代码片段,就将其放入牌组中,无论代码是在代码库、博客,随手写下的笔记还是抓取的屏幕截图中发现的。
为了将代码示例的照片转换为对 Anki 友好的问题/答案对,我创建了一张卡片,放上代码的屏幕截图,截图前面有个问题,大概是这样的:「这个代码好在哪里?」在我的回答中,我将这项技术的优点列成项目符号列表,这样强制自己认清究竟学到什么,并用语言表达出来,而不停留在隐隐约约地无言欣赏。
有时我反过来分析糟糕的代码,制作卡片问「这是怎么回事?」,这样又能针对糟糕代码建立规则或建议。这两个过程的最终目标,都是让我自己编程时快速判断代码质量。
4. 有序信息不易于 Anki 化
一开始,我认为所有的技术知识都能很好地 Anki 化。从那以后,我降低了我的热情,并注意到一个重大例外:顺序/结构至关重要的信息。例如,我制作了大量卡片描述在服务器上设置 SSH 密钥,这是笔记本电脑和远程服务器之间复杂的、多步骤的舞蹈。尽管我借助 Anki 复习,但我从来没有在实践中记起完整的这一有序过程,总是求助于在线指南。我 Anki 化并复习 SSH 秘钥设置规则的时间被浪费了。
我不确定我失败的确切原因。也许我为这类信息创建抽认卡的办法不对,我该多做一些 SSH 卡片,来询问某个步骤在另一个步骤的之前还是之后。但我的直觉是,创建这么多额外的卡片是糟糕的无底洞,我宁愿维护一个这项过程的清单,用的时候再查看。
5. 暂停学习不需要的技术。在需要的时候使用强记模式。
边缘技术是我的工作中偶尔用到的语言、库、功能集和概念,我认为在有限的复习时间里复习这些技术不是很好。某个项目需要边缘技术,这个情境下我会制作相关材料的卡片 (例如,去年在 Web 应用程序中使用 Backbone),但之后我会暂停对这些卡片的复习。如果出现另一个项目也使用该技术,我会在项目开始之前使用 Anki 的强记功能快速复习该技术。如果这样的项目永远不出现,我会无限期地暂停这些卡,也许再也不会使用了。
你可能会指出,为边缘技术制作 Anki 卡片首先很浪费。也许对你来说是浪费,但是
i) 我发现很难在第一次遇到时就能分辨边缘技术和核心技术,而且,
ii) 我发现主动地将技术材料转化为问题和答案这一练习,不仅让我阅读更专注,而且帮助我更快地审视文本以获取可行的信息。
6. 降低强度
标准的 SRS 使用理论(也是 P. Wozniak 所拥护的)要求我们任何一天都要把当天牌组中到期的所有卡片都复习完,才能以最高效率将知识转化为长期记忆。我这么做了差不多两年,但我感觉这样的复习负担太重了。为了应对这个问题,我限制我的编程牌组的最大复习数量为每天 40 张,并修改了 Anki 中的牌组设置,来提升简单奖励 (评分为简单的卡片间隔会增加额外时间),以及间隔修饰符 (任何卡片复习之间的间隔)。这个简单奖励的选项让简单的卡片出示次数更少 (对我来说已不构成挑战了,而且往往是我的牌组中更高级概念的基石,所以这样权衡是合理的),而间隔修饰符调整了算法,让所有卡片之间间隔更大,无论卡片难度,也就是说每次复习之间隔得更久,每天早上需要复习的更少。
我为缩短复习时间付出的代价是,我可能不会沿着「遗忘曲线」复习,这样全局看来是低效的学习策略。我还可以接受,因为我知道编程语言来来去去,而且我意识到 10 年后我可能就不编程了,我的首要目标就是此时此刻,我能飞一般地写程序,能写多快就有多快。此外,如果缩短复习时间,能确保你坚持复习,降低效率是合理的代价,其作用类似困难的减肥节食计划中的欺骗日。
7. 边阅读边编号
我在阅读纸质编程教科书时,一看到我想放进 Anki 里的内容,我便在旁边空白处标号 (1, 2, 3...),再写上简短的提示,如「文件系统效率」。书读完后,我再扫视一遍,要是觉得标号的点还值得记忆,我便添加 Anki 卡片。
我这样做的原因是:i) 要是看到一个点就靠到笔记本电脑前做 Anki 卡片,就会打破阅读的心流,因此批量处理更省时间 ii) 一些教科书作者在后续章节会对一个论点做更深入说明,而我的卡片牌组里只使用最佳描述,所以我这样做。
8. 强调独立于语言的模因
随着我对编程语言和库的学习,我意识到学到在其他语言中重复出现的“模因”,正是在我的第一种编程语言 Ruby 中应用 Janki 方法的部分价值。例如,Ruby 的 Enumerable 模块中的「函数式」方法,如 each(), map(), select(), reject(), zip() 在 Javascript、Lisp、Python 和各种库中(如 Javascript的 Underscore 库)重复出现,名称大抵相同。了解这些函数的含义以及使用方法,可以减少学习新环境所需的时间。类似地,了解 Linux 与文件交互的细节,能让 Ruby、C 和 Python 中的 文件与 IO 交互方法更明晰。
对于区分独立于语言的模因和「此语言独占」的想法,我没有足够简单的办法,只有一些粗略的经验法则。优雅代码和丑陋代码(比如魔数)在其他语言环境中常常有相仿案例(如果还没有,也能很有效地复制过去)与底层的操作系统交互的函数 (线程,IO),只要没有加上抽象,与类似操作系统上运行的语言都共享相同的理念 (linux, Android, iOS, Windows);很多语言的正则表达式很相似 (虽然语法变种很多,这点很烦); 二进制数学、字符编码、性能优化、调试、面向对象编程等概念,在不同语言之间历久弥新。
9. 反复答错后自己执行代码
我若意识到自己多次答错某张卡了,便会在控制台中测试该代码,或者进行类似操作 (例如,对于 Vim 命令,我会在 Vim 中输入快捷键)。我至少这样连着操作两次,这样我的手指就能记住命令,也能向我证明代码能跑起来,并让我理解上下文,由此种种,我下次更有可能记住它。
10. 为卡片的用途头脑风暴。或将其删除。
我复习到的卡片若是包含我从未使用过的编程特性,我便问自己:是这个特性在现实世界里就是没什么用场,还是问题在我,没有下足功夫去找用例?为了回答这个问题,我会结合我手头上的项目进行头脑风暴,来探索这种特性的可能用法,即便有时想的东西很可笑。我得以应用所学的知识,而且要是我找不出合适的用例,我就认输,之后删除这个卡片,裁剪牌组中的不必要内容。
11. 把重点加粗
我们总会想尽办法减少花在复习牌组上的时间。一个简单而有效的解决方案是把问题或答案中的关键字或要点加粗,或者把两者中的关键字都加粗。这个技巧特别适合一些内容相似的卡片,比如一些卡片解释的异常都在同一命名空间或者同一类下面。多年来在网上浏览文本,我们的眼睛很擅长清晰辨识粗体文本,我发现仅仅是在你的 Anki 卡片上看到粗体字体就足以唤起记忆,并激发所需的答案,节省了你原本需要阅读整张卡片的时间。在你的复习中尽可能快地触发记忆,然后继续前进。
不加粗很难浏览
与带有粗体的版本比较
12. 最佳实践卡
无论是通过与更好的程序员配对,观看带有解说的视频,还是阅读 Github 的评论,一旦我了解到一条最佳实践,我都会将其转化为卡片。目前为止还很常规。但在我复习这些卡片时,我采取的办法与普通讲事实的卡片不一样:如果我最近在工作流中没有做到最佳实践,卡片就需要重新来过。与单纯的事实性卡片不一样,仅仅知道最佳实践存在是无济于事的;最佳实践卡片要让我掌握这种实践,而卡片反复失败会带来愧疚,我便会受刺激向最佳实践靠拢。
13. 题目与解说卡
有时你不希望只学习事实,而需要学习一种技术、方法论或心理算法。这时候 (例如,学习二进制数的乘法),我会制作一些卡片,其问题是题目,答案是题目的解答。每当我复习这些卡片,我都会力图解答题目,如果我答案错了,我就会让卡片重新来过。我发现在卡片背面解释我是如何计算出解的 (即方法论),很有必要,这样我就可以提醒自己,如果我做错了,应该怎么做。
比较这两张卡片,一张没有解释:
和一个有解释的:
一个相关的变种做法是,我为某次出错的 bug/命令及其解决办法制作卡片,但附上对该命令的深入解释。
Thoughts Memo 汉化组译制
原文:JANKI METHOD REFINED
更多有关制卡原则的内容,请关注:
制卡原则与知识表述