专业精进之路:构建扎实而有实效的编程知识体系
对世界上任何一件事物保持谦卑求知之心。
在“打造适合自己的知识库”一文中,讲到了构建适合自己的知识库的一些经验和做法,不过,那还仅限于工具之法,并未涉及知识构建之法。本文对编程知识体系的构建作一探讨。
我定的目标是构建扎实而有实效的编程知识体系。扎实,意味着所依赖的知识是坚实的站得住脚的,溯源知识的原理;实效,致力于为人生与生活提供有益的指导和帮助。有实效的,并不一定是非常系统化的。我去除了对“系统化”的执念。
自底向上和自顶向下
构建知识体系的途径有两种方式:自底向上和自顶向下。
自底向上
适合于初学者,对某个知识领域还没有整体观。学一个记一个,有一进一。比如今天接触到哈希表,就仔细学习哈希算法和哈希函数。日有所学,日有所进。日积月累,量变产生质变。
这种过程很像“织网”,“贪婪”地向外扩展,聚焦对单个知识点的理解和掌握。也可以兼顾知识之间的关联。
强烈推荐写技术博客。对于一个工程师而言,由于具体技术的易变,如果不作以记录的话,五年十年之后,你以前的知识随着时光渐渐遗忘,你可能会感觉像是做了一场梦,不知道这些生命时光里究竟收获了什么。
自顶向下
适合于有多年工作经验的人。这时人已经对某个知识领域(比如java 开发)有一定的整体理解和应用,希望能够更系统化地组织知识及知识之间的关联,达到举一反三、触类旁通的境地。
对于有多年工作经验的人,可以结合两种方式使用。首先构建一个类似“计算机编程领域的三十六种基本思想概览”(通过日积月累形成,可以画成思维导图),把所学所用的串起来,然后再针对每一个子主题各个击破,深入掌握。
这种过程很像“收网”,你已经罗住了一筐鱼,但是鱼还在往外跳,一不小心就丢掉了。需要牢固地让鱼乖乖入网。
掌握工程原则
学会写基本的程序之后,下一步要将学会开发软件。
软件是基本程序逻辑单元基于工程原则的有序组合。工程原则在软件开发中起着非常重要的作用。
软件开发考虑的是:在可接受的成本范围内,如何构建可维护、可复用、可扩展、高性能、高可用、稳定可靠以及满足其它质量需求的软件系统(关键质量需求在架构设计前期要确定下来)?最重要的四大工程原则:复用、封装、解耦、组合。
需要深入理解这些工程原则,熟练掌握实现这些工程原则的技术、方法、工具、流程。
这一步需要读一点书籍,在项目实战中去观摩和领会。
掌握编程思想
具体技术知识是非常庞杂、广泛而深入的。如果不能举一反三、触类旁通,领悟其中的道和法则,将会耗费大量时间而迷失方向。这时候,需要掌握编程思想,正是这些编程思想的合理巧妙组合,才构建了无穷多样的技术。技术是易变的,思想是恒定的。这也是我写“计算机编程领域的三十六种基本思想概览”的初衷。通过这种方式,将所学所悟通过一篇文章串联在一起,形成一个知识子体系。
有了工程原则和编程思想的武装,就能理解各种形式的技术思路和做法,达到“通观领悟”的地步。
深入原理实现
对知识的掌握有如下层次:
- 知其然而知其所以然。既有实际的熟练掌握和工作经验,也对其中的原理有深入的理解。
- 知其然而不知所以然。经常用,但是对原理实现一知半解或少有了解。
- 只是了解。知道有这个东西,但没用过,也没有任何经验,更不谈对原理的理解。
- 不知道。根本不知道还这么个东西。全然无知。
对于很多知识,我们常常停留在后面三个层次上。比如,我能熟练使用 linux 管道及命令实现一些小需求,但是我对 linux 管道的实现原理不清楚。比如,我知道有个 .net 框架,但对 windows 技术体系知之甚少。
那么,灵魂拷问来了:你是想学潜龙之法,还是皮毛之技?如果你的选择是后者,那么这部分可以直接跳过了。
专业精进永无止境。在掌握工程原则和编程思想的基础上,就需要对以前用过的了解的知识作原理层面的探究。
有一种办法:每当遇到一个技术点时,自己先思考怎么去实现,需要考量哪些因素,如何权衡和设计。可参考:“技术思考框架:抽象-思路-考量-优化-细节”。
细节也非常重要。往往解决问题的关键之处就隐藏在细节里。如果对细节清晰精准的表达,那么可以说,是真正地知其然而知其所以然了。
注重基础
对于每一个知识点和知识主题,注重打好基础,探问本质。
- 比如数据结构与算法,常用的数组、链表、栈、队列、二叉树、红黑树;分治、递归、动态规划法、查找、排序等。
- 比如并发同步,线程安全的原理是什么?并发的依据是什么?
编程开发知识体系的基础是什么呢?
- 最底层是模型和物理限制;
- 其上是数据结构与算法;
- 再往上是设计与组织;
- 再往上是复用与封装。
- 最上层就是应用层了。
因此,首要理解的就是底层模型、数据结构和算法。
结合工作需求夯实薄弱点
知识体系建设是一项庞大而长期的工程,不大可能从零开始一个个知识点地构建。对于工作多年的人来说,可以结合工作需求及自己的薄弱点,有针对性地夯实。
比如我的薄弱点是:存储、网络、语言编译,其它方面对工作阻碍不大。那么就可以优先夯实存储、网络和语言编译的部分。存储方面,主要是查询原理和查询性能;网络方面,主要是网络拓扑、数据抓包和网络协议编程;语言编译,主要是语言的解析和优化方面。
夯实薄弱点,最好能结合工作需求。学以致用,学后立即用,才能印象深刻,有更好的效果。比如,最近在做软件系统的可用性分析和优化,要用到分布式缓存和本地二级缓存,就可以对缓存进行加固学习和应用。
可以有一个技术研习计划。这个技术研习计划的条目不要过多,否则可能一个都进行不下去(亲身教训)。首要目标是针对工作所遇到的问题和技术,能够做到知其然而知其所以然。
掌握要领
对于比较难的知识点,需要反复理解和操练,直到熟练。
比如容器存储卷和K8S网络模型。初次接触总是比较陌生的。需要多次学习和操练。不能假设自己是天资聪颖,过一遍就会。一回生,两回熟,三次就能带人走。
遇到挫折时,先不要怀疑自己笨或者天赋不够。很可能只是没有掌握要领。思考:这个事情的要领是什么?向擅长此事的人请教。
总结和提炼
知识总结和提炼也是很重要的一环。
知识的总结要注重原理。要探问:它的本质是什么,基础原理是什么? 运用“技术思考框架:抽象-思路-考量-优化-细节”的框架对知识进行“解剖”,直到知其然而知其所以然。
知识总结和提炼宜精炼表达。以列表纲要形式和固定模板来组织条目和依据。删除不必要的字句。能少即少。能够用一行命令或代码表达的,就不必用文字了。
我个人喜欢精练表达的缘故是:1. 学习诗词培养的习惯(因为诗词讲求字字珠玑);2. 大脑容量有限,记不住那么多东西; 3. 没有那么多时间写太啰嗦的话。悟者自悟。
当然,如果是写成面向读者的文章,则需要扩充文字内容,给予必要的示例和解释。
如何兼顾这两种情形呢?平时该咋写就咋写,记录知识和依据。然后单独开辟一篇类似知识索引的文章(比如”互联网应用服务端的常用技术思想与机制纲要),以条目形式展示所有最关键最精髓的思想,见之心明(通常一句话)。这种文章是很考验功力和书面表达能力的。
建立知识大纲
建立知识大纲,有一个整体的概览视图,对于构建编程知识体系是很有益处的。
比如,在笔记里开辟一个“专业精进”的文件夹,含有两个子文件夹:札记和技术文摘。技术文摘是从网络摘录而得,札记则是自己的思考和实践总结而得。技术文摘里的养料会逐渐转化成札记里的笔记。所有编程开发相关的东西都放在这两个子文件夹下。每个子文件夹下,又有多个子主题,这些子主题可以收集各种细分域的内容。常用的技术领域,比如 Java 开发和系统设计,就可以列为子主题。子主题可以分得细一些,这样就能清楚地看到自己在各个细分方面的积累如何。
这个架子搭起来之后,就可以按照上述思路和方法丰富和精炼其中的内容。
整理已有笔记
建立知识大纲之后,快速充实知识体系的一个方法,就是根据知识大纲整理现有的笔记。
网络摘录与自己写的分开放还是放在一起?想了很久,最后决定还是放在一起,不区分彼此。重要的是整合成一个扎实有实效的知识体系,以供日后生活和工作所需,而不是固着于自己所写的。
- 将技术文摘和札记的知识子主题进行重组、合并、细分。
- 将零散的思考按照知识大纲的分类,重新组合,整理成系统化的知识和思考;
- 将零散的网络摘录,按照自己的风格改造;
- 务求精练。
编程知识的投资
知识无穷无尽,穷尽一生亦未必得其一二。那么,对于所要掌握的知识必须有选择性。
在“如何做编程知识投资及减少知识失效的影响”一文中,谈到了编程知识的分类与投资。现在我会更侧重原理、设计性、稀缺经验的知识积累。
掌握良好的技术子集
对于语言学习来说,不是所有的语言特性都需要学习和使用。 学习和使用那些设计不良的特性,不仅耗费大量时间和精力,而且有损项目的可维护性,得不偿失;反之,学习那些优良的部分,不仅可以节省时间,腾出更多时间和精力去做更重要的事情,而且有助于将事情做好,提高收益/学习比。
以上道理同样适用于技术学习与应用。技术知识浩瀚如海,细节如针细。要穷尽是非常困难的。好在,对于一门技术来说,并不需要掌握全部的细节才能工作和创造。 提炼出一门语言或技术的 Good Parts, 使用该子集去构造健壮稳固的应用。
Python 之禅还是有道理的:
There should be one-- and preferably only one --obvious way to do it.
良好的技术子集包含哪些内容呢?可阅:“软件开发之技能梳理”。
制作课程
将知识体系化的更进一步,是制作成课程,可以供别人学习,同时也能创造一些收入。
制作课程,一方面需要有大纲规划,一方面需要根据目标群体做需求调研,将知识更好地提炼出来,传达给他人。制作课程,可以从制作小视频入手。
这也是我接下来会去思考的问题之一。
思维反观
不仅仅是探究具体问题,还要反观自己的思维过程,是如何思考和分析问题的,进行判断和决策的原则、依据、立场何在,有哪些阻滞之处,为何会有这些阻滞,如何从根本上突破自身思维的局限性。所有学习和求解的问题几乎都是思维认知局限性的问题。
比如,有些算法我就理解起来比较绕弯,是因为什么缘故?是我的惯性思维不适应理解算法的某些方面吗?是我的线性思维难以理解事物的非线性特征吗?比如,有些设计方案的决策我就难以确定,是因为什么缘故?是因为相关经验和知识匮乏,还是视野不够开阔?
小结
建设知识库,是一个长期的过程,我相信也会带来很大的后期回报。需要有耐心,有方法,逐步推进深化。