他们都是只有意识没有行动,他们是动力不足的人。
他们都不知道自己该学什么,他们缺乏方向和目标
他们都不具备自主学习的能力,没有正确的方法和技能
更要命的是,他们缺乏实践和坚持

如果你去研究一下古今中外的成功人士,就会发现,他们基本上都是非常自律的,也都是非常热爱学习的。他们可以沉得下心来不断地学习,在学习中不断地思考、探索和实践。所以,如果你不能克服自己 DNA 中的弱点,不能端正自己的态度,不能自律,不能坚持,不能举一反三,不能不断追问等,那么,无论有多好的方法,你都不可能学好。所以,有正确的态度很重要。

学习金字塔
程序员练级 95-99 学习.png

举个大家都懂的例子,那就是学习英文,我们从小就是在开始学习英文了,很多人英文成绩可以考得很好,语法也可以不错。然而,哪天真正要和外国人交流的时候,却发现自己的英文能力渣得不要不要的,只会回答:Fine. Thank you, and you? 这就是浅度学习的结果。

我的英文能力也是一样的,直到有一天进到外企,外企请了个外教每周来公司三次和我们练英文,我的英文能力才有一点点进步,然而,还是不够。后来有一天,公司的客户抱怨我们的一线客服处理问题太慢,问我们在后台做开发的人有谁去一线支持客户,我举手了。于是我接了半年来自日本、新加坡、德国、法国、英国等多个国家的客户电话和邮件。

在这期间,我的英文能力直线上升,速度快得不得了。一方面是我要把自己知道的讲给客户听,另一方面要跟客户有交流,所以我学得更努力,也更有效果。主要是日本人和德国人给了我足够的信心,这两个国家的人可能是这世界上最严谨的人,他们非常喜欢打破沙锅问到底,而且他们的英文也不怎么好,但是他们都用很慢的语速来和我交流,一方面是怕他们自己说不好,另一方面是也希望我用慢速的话和他们说。于是,大家都在一种慢速的环境下说英文,把每个单词的音都发准了,这使我提高了英文能力。

怎样进行深度学习呢?

高质量的信息源和第一手的知识。
把知识连成地图,将自己的理解反述出来。
不断地反思和思辨,与不同年龄段的人讨论。
举一反三,并践行之,把知识转换成技能。

换言之,学习有三个步骤。

知识采集。信息源是非常重要的,获取信息源头、破解表面信息的内在本质、多方数据印证,是这个步骤的关键。
知识缝合。所谓缝合就是把信息组织起来,成为结构体的知识。这里,连接记忆,逻辑推理,知识梳理是很重要的三部分。
技能转换。通过举一反三、实践和练习,以及传授教导,把知识转化成自己的技能。这种技能可以让你进入更高的阶层。

学习不仅仅是为了找到答案,而更是为了找到方法。
只有掌握解题的思路和方法,你才算得上拥有解决问题的能力。所有的练习,所有的答案,其实都是在引导你去寻找一种“以不变应万变”的方法或能力。

让我想到了高中时,自己喜欢数学题的原因,通过不断的归纳整理,找到解决各种问题的通用方法。

学习不仅仅是为了知道,而更是为了思考和理解。在学习的过程中,我们不是为了知道某个事的表面是什么,而是要通过表象去探索其内在的本质和原理。真正的学习,从来都不是很轻松的,而是那种你知道得越多,你的问题就会越多,你的问题越多,你就会思考得越多,你思考得越多,你就会越觉得自己知道得少,于是你就会想要了解更多。如此循环,是这么一种螺旋上升上下求索的状态。

在学习的过程中,我们要不断地问自己,这个技术出现的初衷是什么?是要解决什么样的问题?为什么那个问题要用这种方法解?为什么不能用别的方法解?为什么不能简单一些?……

或许当前在很多方面自己的正反馈较少,使得自己继续反思下去,总结归纳,从而将其转换为兴趣。

学习不仅仅是为了成长,而更是为了改变自己。

评论区:这篇文章推荐扩展阅读《深度工作》《终身成长》《知识大迁移》《你的生存本能正在杀死你》。


所以,学习不是努力读更多的书,盲目追求阅读的速度和数量,这会让人产生低层次的勤奋和成长的感觉,这只是在使蛮力。要思辨,要践行,要总结和归纳,否则,你只是在机械地重复某件事,而不会有质的成长的。

种种迹象表明,快速、简单、轻松的方式给人带来的快感更强烈,而高层次的思考、思辨和逻辑则被这些频度高的快餐信息感所弱化。于是,商家们看到了其中的商机,看到了如何在这样的时代里怎么治愈这些人在学习上的焦虑,他们在想方设法地用一些手段推出各种代读、领读和听读类产品,让人们可以在短时间内体会到轻松获取知识的快感,并产生勤奋好学和成长的幻觉(老实说,像我这种付费专栏或是得到等知识付费产品基本上就是类似的产物)。

这些所谓的“快餐文化”可以让你有短暂的满足感,但是无法让你有更深层次的思考和把知识转换成自己的技能的有效路径,因为那些都是需要大量时间和精力的付出,不符合现代人的生活节奏。人们开始在朋友圈、公众号、得到等这样的地方进行学习,导致他们越学越焦虑,越学越浮燥,越学越不会思考。于是,他们成了“什么都懂,但依然过不好这一生”的状态。

只要你注意观察,就会发现,少数的精英人士,他们在训练自己获取知识的能力,他们到源头查看第一手的资料,然后,深度钻研,并通过自己的思考后,生产更好的内容。而绝大部分受众享受轻度学习,消费内容。

Tip

简单、轻松、快速的知识给人们带来的快感更高,因此商家看到了其中的商机,并生产各种简单、轻松、快速的知识供消费者使用,给消费者带来学到知识的感觉。

同时,我突然意识到,虽然自己没有陷入到朋友圈/公众号/抖音等低质的信息中,我还是陷入到了 B 站的 “高质” 信息中。B 站知识区 Up 主的视频是否高质量?相对于公众号、抖音或许真的属于高质量,但是这是 Up 主们加工后的产物。相对于一本本深奥的书籍来说,恰恰满足简单、轻松、快速的特点,而自己就陷入到这样的 “高质” 信息中。

仔细回想一下,在 B 站看到的很多知识类视频其实并没有真正的被我记住或者用到,一方面是自己没有去回顾记忆,另一方面确实一部分知识无法贴合自身需求 or 无法应用到实际。


优质信息源

Medium 上的文章质量比较高,很多文章都 Google 到了 Medium 上。

emmm,但是应该不至于直接看 Medium,娱乐时间可以看,但是没必要专门去看。毕竟一切琐碎的知识都不利于学习。

注重基础 & 灵活运用

举个例子,如果你学习过底层的 Socket 编程,了解多路复用和各种 I/O 模型的话(select, poll, epoll, aio, windows completion port, libevent 等),那么,对于 Node.js、Java NIO、Nginx、C++的 ACE 框架等这些中间件或是编程框架,你就会发现,无论表现形式是什么样的,其底层原理都是一个样的。

无论是 JVM 还是 Node,或者是 Python 解释器里干了什么,它都无法逾越底层操作系统 API 对“物理世界”的限制。而当你了解了这个底层物理世界以后,无论那些技术玩成什么花样,它们都无法超出你的掌控(这种感觉是很爽的)。

再举一个例子,当学了足够多的语言,并有了丰富的实践后,你开始对编程语言的各种编程范式或是控制流有了原理上的了解,这时再学一门新语言的话,你会发现自己学得飞快。就像我 2010 年学习 Go 语言一样,除了那些每个语言都有的 if-else、 for/while-loop、 function 等东西以外,我重点在看的就是,出错处理是怎么玩的?内存管理是怎么玩的?数据封装和扩展怎么玩的?多态和泛型怎么搞的?运行时识别和反射机制是怎么玩的?并发编程怎样玩?……

最最关键的是,这些基础知识和原理性的东西和技术,都是经历过长时间的考验的,所以,这些基础技术也有很多人类历史上的智慧结晶,会给你很多启示和帮助。比如:TCP 协议的状态机,可以让你明白,如果你要设计一个异步通信协议,状态机是一件多么重要的事,还有 TCP 拥塞控制中的方式,让你知道,设计一个以响应时间来限流的中件间是什么样的。

知识图

于是我自己发明了一种叫“联想记忆法”的方法,比如,在学习 C++的时候,面对《C++ Primer》这种厚得不行的书,我就使用联想记忆法。我把 C++分成三部分。

第一部分是 C++是用来解决 C 语言的问题的,那么 C 语言有什么问题呢?指针、宏、错误处理、数据拷贝…… C++用什么技术来解决这些问题呢?

第二部分是 C++的面向对象特性:封装、继承、多态。封装,让我想到了构造函数、析构函数等。构造函数让我想到了初始化列表,想到了默认构造函数,想到了拷贝构造函数,想到了 new……多态,让我想到了虚函数,想到了 RTTI,RTTI 让我想到了 dynamic_cast 和 typeid 等。

第三部分是 C++的泛型编程。我想到了 template,想到了操作符重载,想到了函数对象,想到 STL,想到数据容器,想到了 iterator,想到了通用算法,等等。

于是,我通过“顺藤摸瓜”的方式,从知识树的主干开始做广度或是深度遍历,于是我就得到了一整棵的知识树。这种“顺藤摸瓜”的记忆方式让我记住了很多知识。最重要的是,当出现一些我不知道的知识点时,我就会往这棵知识树上挂,而这样一来,也使得我的学习更为系统和全面。这种画知识图的方式可以让你从一个技术最重要最主干的地方出发开始遍历所有的技术细节,也就是画地图的方式。如果你不想在知识的海洋中迷路,你需要有一份地图,所以,学习并不是为了要记忆那些知识点,而是为了要找到一个知识的地图,你在这个地图上能通过关键路径找到你想要的答案。

评论:受益匪浅,感触比较深的是这两三年,为跟上技术的发展,去系统的接触微服务、ML、区块链等,才发现英语不行对查找并获得最有价值的内容的阻碍,经常是筛选的好内容原来只是翻译,而且还只是翻译一部分,另外也发现阻碍学习的不是工作忙时间不够,反而是基础不扎实,学习新系统新框架新语言不得不一次一次去翻查操作系统原理、网络协议、语言特性,尤其痛苦学习 ML,完全暴露数学没基础,唯独有安慰的一点也是如耗子哥所说的,面对知识的海洋,要有知识的地图,自己现在也是这么做,把一个大的领域放入思维导图,梳理的知识往图上挂,至少感觉可以沉下来学了


代码 vs 文档

代码 —— 了解实现细节,how
文档 —— 了解实现背景,why

如何阅读代码?

在阅读代码之前,我建议你需要有下面的这些前提再去阅读代码,这样你读起代码来会很顺畅。

  1. 基础知识。相关的语言和基础技术的知识。
  2. 软件功能。你先要知道这个软件完成的是什么样的功能,有哪些特性,哪些配置项。你先要读一遍用户手册,然后让软件跑起来,自己先用一下感受一下。
  3. 相关文档。读一下相关的内部文档,Readme 也好,Release Notes 也好,Design 也好, Wiki 也好,这些文档可以让你明白整个软件的方方面面。如果你的软件没有文档,那么你只能指望这个软件的原作者还在,而且他还乐于交流。
  4. 代码的组织结构。也就是代码目录中每个目录是什么样的功能,每个文档是干什么的。如果你要读的程序是在某种标准的框架下组织的,比如:Java 的 Spring 框架,那么恭喜你, 这些代码不难读了。

你要了解这个软件的代码是由哪些部分构成的,我在这里给你一个列表,供你参考。

  1. 接口抽象定义。任何代码都会有很多接口或抽象定义,其描述了代码需要处理的数据结构 或者业务实体,以及它们之间的关系,理清楚这些关系是非常重要的。

  2. 模块粘合层。我们的代码有很多都是用来粘合代码的,比如中间件(middleware)、 Promises 模式、回调(Callback)、代理委托、依赖注入等。这些代码模块间的粘合技术 是非常重要的,因为它们会把本来平铺直述的代码给分裂开来,让你不容易看明白它们的 关系。

  3. 业务流程。这是代码运行的过程。一开始,我们不要进入细节,但需要在高层搞清楚整个 业务的流程是什么样的,在这个流程中,数据是怎么被传递和处理的。一般来说,我们需 要画程序流程图或者时序处理图。

  4. 具体实现。了解上述的三个方面的内容,相信你对整个代码的框架和逻辑已经有了总体认 识。这个时候,你就可以深入细节,开始阅读具体实现的代码了。对于代码的具体实现, 一般来说,你需要知道下面一些事实,这样有助于你在阅读代码时找到重点。

代码逻辑。代码有两种逻辑,一种是业务逻辑,这种逻辑是真正的业务处理逻辑;另一 种是控制逻辑,这种逻辑只是用控制程序流转的,不是业务逻辑。比如:flag 之类的控 制变量,多线程处理的代码,异步控制的代码,远程通讯的代码,对象序列化反序列化 的代码等。这两种逻辑你要分开,很多代码之所以混乱就是把这两种逻辑混在一起了 (详情参看《编程范式游记》)。

出错处理。根据二八原则,20%的代码是正常的逻辑,80%的代码是在处理各种错误, 所以,你在读代码的时候,完全可以把处理错误的代码全部删除掉,这样就会留下比较 干净和简单的正常逻辑的代码。排除干扰因素,可以更高效地读代码。

数据处理。只要你认真观察,就会发现,我们好多代码就是在那里倒腾数据。比如 DAO、DTO,比如 JSON、XML,这些代码冗长无聊,不是主要逻辑,可以不理。

重要的算法。一般来说,我们的代码里会有很多重要的算法,我说的并不一定是什么排 序或是搜索算法,可能会是一些其它的核心算法,比如一些索引表的算法,全局唯一 ID 的算法、信息推荐的算法、统计算法、通读算法(如 Gossip)等。这些比较核心的算法 可能会非常难读,但它们往往是最有技术含量的部分。

底层交互。有一些代码是和底层系统的交互,一般来说是和操作系统或是 JVM 的交互。 因此,读这些代码通常需要一定的底层技术知识,不然,很难读懂。

  1. 运行时调试。很多时候,代码只有运行起来了,才能知道具体发生了什么事,所以,我们让代码运行进来,然后用日志也好,debug 设置断点跟踪也好。实际看一下代码的运行过程,是了解代码的一种很好的方式。

总结一下,阅读代码的方法如下:

一般采用自顶向下,从总体到细节的“剥洋葱皮”的读法。
画图是必要的,程序流程图,调用时序图,模块组织图…
代码逻辑归一下类,排除杂音,主要逻辑才会更清楚。
debug 跟踪一下代码是了解代码在执行中发生了什么的最好方式。


如何更好的学习?

1.建立知识图 2.多问自己为什么 3.在学习新技术时应用学习模板去思考

学习模板 1.这个技术出现的背景是?要解决的问题是? 2.这个技术的优势和劣势,trade-off 是什么? 3.这个技术适用的场景。场景包含业务场景和技术场景。 4.技术的核心思想和核心组件 5.技术的底层原理和关键实现 -底层的关键基础技术可能也是其他技术的关键基础技术 -可以看 coolshell 上写的 docker 底层技术系列文章 6.现有实现与该技术的对比,不同技术有不同的实现侧重、不同的思路,开阔思维

评论:
高铁产生的背景和成因
高铁应用场景
高铁组成部分
高铁设计原理
高铁优势和劣势
高铁和火车对比

如何举一反三

1.联想能力 - 同一个事物的不同用法,或者联系与之有关的其他事物 2.抽象能力 - 找到解决问题的通用模型 3.自省能力 - 左右互搏,站在对立面来找自己的漏洞

1.对于一个场景,制造出各种不同的问题或难题。
2.对于一个问题,努力寻找尽可能多的解,并比较这些解的优劣。 3.对于一个解,努力寻找各种不同的测试案例,以图让其健壮。

如果你在 Coolshell 上看过我写的《TCP 的那些事儿》,你就能知道我对《TCP/IP 详解》这本这么厚的书以及一些日常工作经验的总结,我写成了两篇比较简单的博客。你需要像我一样扩大自己的知识面,然后学会写博客,就能慢慢地拥有这种能力了。这种将信息删减、精炼和归纳的方法,可以让你的学习能力得到快速的提升。当你这么做的时候,一方面是在锻炼你抓重点的能力,另一方面是在锻炼你化繁为简的能力。这两种能力都是让你高效学习的能力。

那些大公司里的开发人员,写完代码,自己不测试,自己也不运维,我实在不知道他们怎么可能明白什么是好的设计,好的软件?

前段时间,我在我的读者群中发起了一个名为 ARTS 的活动。每人每周写一个 ARTS:Algorithm 是一道算法题,Review 是读一篇英文文章, Technique/Tips 是分享一个小技术,Share 是分享一个观点。

一方面你要把你的坚持形成成果晒出来,让别人来给你点赞,另一方面,你还要把坚持变成一种习惯,就像吃饭喝水一样,你感觉不到太多的成本付出。只有做到这两点,你才能够真正坚持。