速读#
过去一年,我最常见的学习错觉是“教程跑通了,所以我会了”。真正需要再次使用时,路由、Git 分支和 Nginx 参数却要从头搜索。后来我把自己的流程改成四步:先复现一条已知路径,再一次只改一个变量,接着脱离资料讲清因果,最后隔几天重新完成一个相近任务。能运行只证明环境接受了当前输入,能够迁移和纠错才更接近掌握。
写博客在这套流程里不是最后的成果包装,而是一种检查。写到“为什么”时卡住,就说明理解仍然依赖教程;但写出来也不自动等于学会,如果文章只是把资料换个说法,几周后仍然取不出来。对我最有效的是先自己复述,再回到文档核对,最后把错误和边界一起修进文章。
2025 年,我一直在重复学同样的东西#
2025 年 3 月,我照教程写过一个 Flask 小项目,当时路由、请求和响应都能工作;7 月做自动化脚本再次调用接口时,却几乎从头查了一遍。5 月折腾过 Git 分支,国庆帮朋友合代码时仍然说不清 merge 与 rebase 分别改变什么;9 月配置过 Nginx 反向代理,11 月别人问 proxy_pass 末尾斜杠会怎样影响 URI,我只记得“这里容易出错”,却解释不出规则。
这些经历过去被我归因于记性差,于是解决办法总是多做笔记。结果笔记散在几个应用里,保存了很多命令和截图,真正需要时仍然不想翻。后来我才意识到,问题首先发生在学习当天:我把照着材料完成一次当成了独立能力,记录下来的又是教程路径,而不是自己怎样判断。
“见过”会带来熟悉感,熟悉感很容易冒充理解。代码在屏幕上出现过、命令成功执行过,我就觉得下一次仍然能做到;但把资料合上以后,大脑并没有建立从问题到步骤的检索路径,也没有经历过错误分支,所以一换环境就失效。这不是单纯忘得快,而是最初的掌握程度就被高估了。
能认出来,与能取出来是两种状态#
后来我读到认知科学中的 retrieval practice,也就是主动提取。Roediger 与 Karpicke 的测试增强学习研究比较了重复阅读与主动回忆:短期内重复阅读可能感觉更熟,延迟测试中,尝试从记忆取回内容通常保留得更好。对我有用的不是把论文变成新口号,而是它解释了为什么“看答案时全懂,关掉页面就不会”。
主动提取也不是凭空硬想。回忆后需要及时反馈,否则错误同样可能被记住;内容还要隔一段时间再次出现,才知道它是留在长期记忆里,还是只靠刚看过的工作记忆。对技术学习来说,最直接的反馈就是程序行为、测试、日志和官方文档:先写出自己的解释和预测,再运行或查证,而不是一开始就盯着正确答案复述。
因此,“能讲出来”只是中间标准,不是终点。真正有用的讲解应当脱离原教程,说明输入、输出、关键约束、常见失败和验证方式;几天后面对一个相近但不相同的问题,还能重新组合这些知识,才证明它开始具备迁移能力。
我现在使用的四步流程#
| 步骤 | 实际动作 | 要避免的错觉 |
|---|---|---|
| 复现 | 按官方文档或可靠教程跑通最小例子,保存版本和环境 | 一次成功就等于已经理解 |
| 单变量实验 | 每次只改一个参数,先预测结果,再观察日志或输出 | 同时改很多地方,最后不知道哪项起作用 |
| 脱稿解释 | 关掉教程,用自己的话写出机制、边界和排查顺序 | 对着原文改写也当成主动回忆 |
| 延迟复做 | 隔几天重新搭建或解决一个相近问题,再核对遗漏 | 当天流畅就认为以后仍会 |
以 Nginx 的 proxy_pass 为例,我不会再只复制一份可工作的 server block。先准备一个能回显请求路径的后端,分别配置带斜杠与不带斜杠的上游地址,每次只改这一处,提前写下我认为后端会收到的 URI,再用 curl 和访问日志核对。随后关掉资料,解释 Nginx 怎样替换 location 前缀;几天后换一个 location 结构重新配置。如果预测错了,错误本身会成为比“记住模板”更稳的锚点。
“故意改坏”也因此变得更精确。随机删除几行只会制造噪声,单变量故障才有学习价值:停掉依赖观察超时,改错一个端口区分拒绝与超时,拿掉一个转发头观察应用怎样判断协议。实验前先知道怎样恢复,生产数据和真实服务器也不拿来练习破坏性操作。
写博客为什么对我有效#
写作会迫使我填上教程经常略过的连接词:为什么先做这一步,另一种写法差在哪里,失败时先看什么。真正卡住的通常不是命令,而是因果关系;为了把一段话写清楚,我会回去重跑最小例子、查原始文档,或者承认自己只知道现象、不知道机制。文章因此成为理解过程的一部分,而不是“学完以后顺手总结”。
但公开写作也可能制造另一种表演性熟悉感。引用很多资料、列出完整配置,看起来很扎实,作者本人却未必能在新环境中重做。现在我更愿意在文章里标明哪些命令实际运行过、哪些结论来自文档、哪些只是小规模实验,以及最后一次验证的版本。写不出的地方不靠更流畅的措辞遮住,直接留下限制或待验证项。
博客还有一个现实作用:它把间隔复习变成自然发生的维护。软件版本变化、读者指出问题、自己再次部署时,我会回到旧文,比较当前行为与当时记录;如果文章无法指导现在的我排障,它就需要修订。Git 历史和 updatedDate 让这种变化可见,比追求一篇永远正确的初稿更符合技术内容的实际寿命。
抽象可以迁移,但不能硬说成同一件事#
学透一个领域后,相邻领域确实会更快,因为一些思考方式能够迁移:API、Java interface 和容器网络都要求我识别边界与契约,组件库之间也共享状态、属性和组合等概念。但它们不是同一个技术对象,不能因为都能用“接口”解释,就忽略语言类型系统、HTTP 协议和网络隔离的具体差异。
迁移的正确用法是生成假设,而不是直接宣布理解。看到新系统时,我可以先问“这里的边界在哪里、双方遵守什么约定”,然后再学习它独有的失败方式。旧经验帮我更快找到问题,却不能替代新领域的文档和实验。所谓慢功夫带来的速度,来自已经形成的提问框架,不是所有技术底层都完全相同。
这套方法也有成本和边界#
不是每个命令参数都值得写一篇文章,也不是每个工具都需要从源码开始理解。低频、可随时查询且出错代价小的信息,留一条可靠笔记已经够用;生成代码中的普通样板可以交给测试验证,把有限精力放在影响行为、安全、数据和后续修改的关键机制上。学习闭环的目的不是把所有知识装进脑子,而是知道哪些必须掌握,哪些可以安全地依赖外部记忆。
这套方法也比照教程慢。一个小例子要多做预测、故障和延迟复现,短期完成数量会下降,所以我只对真正要长期使用的技能做完整闭环。门槛必须足够低:解决一个真实问题后留下一段可复现记录,隔几天再用一次,而不是给自己安排每天输出长文的计划。从开博到现在,能持续的也正是这种“问题发生后顺手整理”的节奏,而不是年初那些靠意志力维持的宏大清单。
我现在判断“学会”的标准很朴素:资料关掉后能重新做,参数变化后能预测,结果不对时知道先去哪一层找证据。跑通是第一步,讲清楚是检查,隔一段时间还能迁移,才算这项知识真正留了下来。
