新的开始

写在前面

今天开始正式开通博客,开始自己的博客之旅,本博客的作用在于平时的归纳总结。下面引用我对耗子叔关于学习态度的总结

端正学习态度

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

人们开始在朋友圈、公众号、得到等这样的地方进行学习,导致他们越学越焦虑,越学越浮燥,越学越不会思考。于是,他们成了“什么都懂,但依然过不好这一生”的状态。

高质量的信息源和第一手的知识。

把知识连成地图,将自己的理解反述出来。

不断地反思和思辨,与不同年龄段的人讨论。

举一反三,并践行之,把知识转换成技能

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

知识采集。信息源是非常重要的,获取信息源头、破解表面信息的内在本质、多方数据印证,是这个步骤的关键。

知识缝合。所谓缝合就是把信息组织起来,成为结构体的知识。这里,连接记忆,逻辑推理,知识梳理是很重要的三部分。

技能转换。通过举一反三、实践和练习,以及传授教导,把知识转化成自己的技能。这种技能可以让你进入更高的阶层。

学习不仅仅是为了找到答案,而更是为了找到方法。

学习不仅仅是为了知道,而更是为了思考和理解。

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

学习不仅仅是为了开拓眼界,而更是为了找到自己的未知,为了了解自己。

开拓眼界的目的就是发现自己的不足和上升空间,从而才能让自己成长。

学习是为了改变自己的思考方式,改变自己的思维方式,改变自己与生俱来的那些垃圾和低效的算法。总之,学习让我们改变自己,行动和践行,反思和改善,从而获得成长。

不能只会用,而不知道为什么要用。

源头、原理和知识地图

信息源要有下面几个特质:

应该是第一手资料,不是被别人理解过、消化过的二手资料。尤其对于知识性的东西来说,更是这样。应该是原汁原味的,不应该是被添油加醋的。

应该是有佐证、有数据、有引用的,或是有权威人士或大公司生产系统背书的资料。应该是被时间和实践检验过的,或是小心求证过的,不是拍脑袋野路子或是道听途说出来的资料。

应该是加入了一些自己的经验和思考,可以引发人深思的,是所谓信息的密集很大的文章

有时候,学习就像拉弓蓄力一样,学习基础知识感觉很枯燥很不实用,工作上用不到,然而学习这些知识是为了未来可以学得更快。基础打牢,学什么都快,而学得快就会学得多,学得多,就会思考得多,对比得多,结果是学得更快……这种感觉,对于想速成的人来说,很难体会。

注重基础知识和原理上的学习

深度,归纳和坚持实践

系统地学习

这个技术出现的背景、初衷和要达到什么样的目标或是要解决什么样的问题。这个问题非常关键,也就是说,你在学习一个技术的时候,需要知道这个技术的成因和目标,也就是这个技术的灵魂。如果不知道这些的话,那么你会看不懂这个技术的一些设计理念。

这个技术的优势和劣势分别是什么,或者说,这个技术的 trade-off 是什么。任何技术都有其好坏,在解决一个问题的时候,也会带来新的问题。另外,一般来说,任何设计都有 trade-off(要什么和不要什么),所以,你要清楚这个技术的优势和劣势,以及带来的挑战。

这个技术适用的场景。任何技术都有其适用的场景,离开了这个场景,这个技术可能会有很多槽点,所以学习技术不但要知道这个技术是什么,还要知道其适用的场景。没有任何一个技术是普适的。注意,所谓场景一般分别两个,一个是业务场景,一个是技术场景。

技术的组成部分和关键点。这是技术的核心思想和核心组件了,也是这个技术的灵魂所在了。学习技术的核心部分是快速掌握的关键。

技术的底层原理和关键实现。任何一个技术都有其底层的关键基础技术,这些关键技术很有可能也是其它技术的关键基础技术。所以,学习这些关键的基础底层技术,可以让你未来很快地掌握其它技术。可以参看我在 CoolShell 上写的 Docker 底层技术那一系列文章。

已有的实现和它之间的对比。一般来说,任何一个技术都会有不同的实现,不同的实现都会有不同的侧重。学习不同的实现,可以让你得到不同的想法和思路,对于开阔思维,深入细节是非常重要的。

举一反三

联想能力。这种能力的锻炼需要你平时就在不停地思考同一个事物的不同的用法,或是联想与之有关的其他事物。对于软件开发和技术学习也一样。

抽象能力。抽象能力是举一反三的基本技能。平时你解决问题的时候,如果你能对这个问题进行抽象,你就可以获得更多的表现形式。抽象能力需要找到解决问题的通用模型,比如数学就是对现实世界的一种抽象。只要我们能把现实世界的各种问题建立成数据模型(如,建立各种维度的向量),我们就可以用数学来求解,这也是机器学习的本质。

自省能力。所谓自省能力就是自己找自己的难看。当你得到一个解的时候,要站在自己的对立面来找这个解的漏洞。有点像左右手互博。这种自己和自己辩论的能力又叫思辨能力。将自己分裂成正反方,左右方,甚至多方,站在不同的立场上来和自己辩论,从而做到不漏过一个 case,从而获得完整全面的问题分析能力。

训练方法

对于一个场景,制造出各种不同的问题或难题。

对于一个问题,努力寻找尽可能多的解,并比较这些解的优劣。

对于一个解,努力寻找各种不同的测试案例,以图让其健壮。

归纳总结

学习的开始阶段,可以不急于总结归纳,不急于下判断,做结论,而应该保留部分知识的不确定性,保持对知识的开放状态。当对整个知识的理解更深入,自己站的位置更高以后,总结和归纳才会更有条理。总结归纳更多是在复习中对知识的回顾和重组,而不是一边学习一边就总结归纳。

把你看到和学习到的信息,归整好,排列好,关联好,总之把信息碎片给结构化掉,然后在结构化的信息中,找到规律,找到相通之处,找到共同之处,进行简化、归纳和总结,最终形成一种套路,一种模式,一种通用方法。

坚持不懈

人不怕笨,怕的是懒,怕的是找到各种理由放弃。

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

如何学习和阅读代码

代 码 => What, How & Details

文档 / 书 => What, How & Why

书和文档是人对人说的话,代码是人对机器说的话

  1. 如果你想知道人为什么要这么搞,那么应该去看书;
  2. 如果你要知道让机器干了什么?那你应该看代码!
  3. 如果你想了解一种思想,一种方法,一种原理,一种思路,一种经验,恐怕,读书和读文档会更有效率一些
  4. 如果你想了解的就是具体细节,比如某协程的实现,某个模块的性能,某个算法的实现,那么你还是要去读代码的(尤其是对于一些 edge case 或是代码技巧方面的内容)

如果你是个新手,那应该多读代码,多动手写代码

如果你是个老手,你有多年的“感性认识”了,那么你的成长需要更多的“理性认识”。这个阶段,你会喜欢读好的书和文章。

如何阅读源代码

  1. 基础知识。相关的语言和基础技术的知识。
  2. 软件功能。你先要知道这个软件完成的是什么样的功能,有哪些特性,哪些配置项。你先要读一遍用户手册,然后让软件跑起来,自己先用一下感受一下。
  3. 相关文档。读一下相关的内部文档,Readme 也好,Release Notes 也好,Design 也好,Wiki 也好,这些文档可以让你明白整个软件的方方面面。如果你的软件没有文档,那么,你只能指望这个软件的原作者还在,而且他还乐于交流。
  4. 代码的组织结构。也就是代码目录中每个目录是什么样的功能,每个文档是干什么的。如果你要读的程序是在某种标准的框架下组织的,比如:Java 的 Spring 框架,那么恭喜你,这些代码不难读了。
  5. 接口抽象定义。任何代码都会有很多接口或抽象定义,其描述了代码需要处理的数据结构或者业务实体,以及它们之间的关系,理清楚这些关系是非常重要的。
  6. 模块粘合层。我们的代码有很多都是用来粘合代码的,比如中间件(middleware)、Promises 模式、回调(Callback)、代理委托、依赖注入等。这些代码模块间的粘合技术是非常重要的,因为它们会把本来平铺直述的代码给分裂开来,让你不容易看明白它们的关系。
  7. 业务流程。这是代码运行的过程。一开始,我们不要进入细节,但需要在高层搞清楚整个业务的流程是什么样的,在这个流程中,数据是怎么被传递和处理的。一般来说,我们需要画程序流程图或者时序处理图
  8. 具体实现。
    1. 代码逻辑。代码有两种逻辑,一种是业务逻辑,这种逻辑是真正的业务处理逻辑;另一种是控制逻辑,这种逻辑只是用控制程序流转的,不是业务逻辑。比如:flag 之类的控制变量,多线程处理的代码,异步控制的代码,远程通讯的代码,对象序列化反序列化的代码等。这两种逻辑你要分开,很多代码之所以混乱就是把这两种逻辑混在一起了(详情参看《编程范式游记》)。
    2. 出错处理。根据二八原则,20% 的代码是正常的逻辑,80% 的代码是在处理各种错误,所以,你在读代码的时候,完全可以把处理错误的代码全部删除掉,这样就会留下比较干净和简单的正常逻辑的代码。
    3. 排除干扰因素,可以更高效地读代码。数据处理。只要你认真观察,就会发现,我们好多代码就是在那里倒腾数据。比如 DAO、DTO,比如 JSON、XML,这些代码冗长无聊,不是主要逻辑,可以不理。
    4. 重要的算法。一般来说,我们的代码里会有很多重要的算法,我说的并不一定是什么排序或是搜索算法,可能会是一些其它的核心算法,比如一些索引表的算法,全局唯一 ID 的算法、信息推荐的算法、统计算法、通读算法(如 Gossip)等。这些比较核心的算法可能会非常难读,但它们往往是最有技术含量的部分。
    5. 底层交互。有一些代码是和底层系统的交互,一般来说是和操作系统或是 JVM 的交互。因此,读这些代码通常需要一定的底层技术知识,不然,很难读懂。

总结:

一般采用自顶向下,从总体到细节的“剥洋葱皮”的读法。

画图是必要的,程序流程图,调用时序图,模块组织图……

代码逻辑归一下类,排除杂音,主要逻辑才会更清楚。

debug 跟踪一下代码是了解代码在执行中发生了什么的最好方式。

认真阅读文档

其它几个实用的技巧

用不同的方式来学习同一个东西。比如:通过看书,听课,创建脑图,写博客,讲课,解决实际问题,等等。

不要被打断。被打断简直就是学习的天敌,所以,你在学习的时候,最好把手机设置成勿扰模式放在一边,然后把电脑上的所有通知也关掉,最好到一个别人找不到你的地方。

总结压缩信息。当你获得太多的信息时,你需要有一个“压缩算法”。我常用的压缩算法是只关心关键点,所以,你需要使用表格、图示、笔记或者脑图来帮助你压缩信息。

把未知关联到已知。把你新学的知识点关联到已知的事物上来。比如,你在学习 Go 语言,你就把一些知识关联到自己已经学过的语言上比如 C 和 Java。通过类比,你会学得更扎实,也会思考得更多。

用教的方式来学习。你想想,如果你过几天要在公开场合对很多人讲一个技术,那么这个压力会让你学得更好。因为要教给别人,所以,这么高的标准需要你不但要把自己已掌握的东西学好,还要把周边的也一并学了,才可能做到百问不倒。你才敢去教别人,不是么?(试试教 6 岁的孩子编程,如果你掌握了这种技能,那么你一定是把知识吃得非常透彻了。)

学以致用。把学到的东西用起来,没有什么比用起来能让你的知识更巩固的了。在实践中,你才会有更为真实的体会,你才会遇到非常细节和非常具体的问题,这些都会让你重新思考,或深化学习。

不要记忆。聪明的人不会记忆知识的,他们会找方法,那些可以推导出知识或答案的方法。**这也是为什么外国人特别喜欢方法论。

多犯错误。犯错会让你学得到更多,通过错误总结教训,你会比没有犯过错的人体会得更深。但是千万不要犯低级错误,也不要同一个错误犯两次。

posted @ 2022-02-17 15:02  WeaveOwn  阅读(87)  评论(0编辑  收藏  举报