They felt that the SICP curriculum no longer prepared engineers for what engineering is like today.
Sussman said that in the 80s and 90s, engineers built complex systems by combining simple and well-understood parts. The goal of SICP was to provide the abstraction language for reasoning about such systems.
Today, this is no longer the case. Sussman pointed out that engineers now routinely write code for complicated hardware that they don’t fully understand (and often can’t understand because of trade secrecy.)
The same is true at the software level, since programming environments consist of gigantic libraries with enormous functionality.
**2. Android业务开发 vs Android动态化框架**
它们都是Android相关的开发,我们假设一个是做业务开发,一个是开发动态化框架,那么它们的基础能力差异如下表所示:
## 细化基础范围:技能图谱
明确了“工作相关”这个原则之后,提升基础的第一步,就是使用**技能图谱**的方式,从以下4个维度来细化基础能力的范围。
1. **工具**:工作中常用的工具,比如IDE、编程语言、问题定位工具和版本管理工具等。
1. **生态**:系统或者产品运行时依赖的所有组件或者系统,比如第三方库、中间件、数据库、文件系统和游戏引擎等。
1. **容器**:系统或者产品在哪里运行,比如Android、iOS、Linux、浏览器和云服务器等。
1. **原理**:需要掌握的原理知识,常见的有计算机网络和数据结构等。
我们以前端开发为例,基础能力的范围如下图所示:
注:
1. 上图仅为示例,不代表完整的前端领域基础能力范围。
1. 图中没有涵盖“JavaScript编程语言”,因为这个可以说是核心能力,不是基础能力。
有了技能图谱之后,我们就能够大致地了解每个技术领域的基础能力到底包括哪些了。
## 提升技术的技巧
明确了基础能力的定义和范围,我们就可以把有限的时间和精力用在更有价值的地方,避免眉毛胡子一把抓,从而实现投入产出效率的最大化。
但是,单个基础技术怎么学,这也很关键,否则学习还是可能事倍功半。
### 常见学习误区
常见的学习误区有两个。第一个是认为,**既然是基础技术,那肯定是掌握得越深越好**,比如数据结构和算法、计算机网络和操作系统这些,几乎是所有程序员的基础,所以每一项都应该深入了解。
但是这样做还是会导致你浪费很多时间和精力。
以数据结构和算法为例,很多人学习的时候都采用了背代码的方式,认为只有自己能手写这些代码,才算是真正的掌握。
而且,有些面试官在面试的时候喜欢让应聘者写简单的算法代码,进一步强化了这样的认知。
我就曾经跟几个这样的面试官聊过,对话过程几乎一模一样,很有意思:
问:“为什么你们要用这种方式来判断应聘者的水平?”
答:“如果一个程序员连个简单的算法都写不出,那就说明他肯定不合格!”
问:“那你们要自己修改算法和写数据结构吗?”
答:“怎么可能?直接用Java库里面的,自己写的质量怎么跟Java库的比啊?”
问:“一般你们考什么算法和数据结构?”
答:“冒泡啊、快排啊、链表、字符串之类的?”
问:“那为什么你们不要求手写B+树,不手写ConcurrentHashMap这些呢?这些难度更高。”
答:这个要求有点高啊,现场写不完,其实我自己也写不出……
在上面的对话中,我们可以看到,其实这种面试方式就属于“面试造航母,工作拧螺丝”,不能判断应聘者水平高低,只能反映出他们面试准备程度的高低;而且能考的也就是这几个简单的数据结构和算法题目,因为面试官自己也只能看懂这几个。
第二个误区是认为,**要完全掌握基础,一定要掌握源码**。
这个观点更加容易导致你投入大量时间却没什么收获。尤其是Linux内核源码、JVM虚拟机源码和MySQL源码这些,如果你不具备深厚的C/C++的开发功力,基本上连看都看不懂,更不用说考虑代码规模和复杂度了。
即便是Netty这些代码相对少一些的开源项目,就算你拥有很强的Java开发技术,要想每一行代码都了解,也要花非常多的时间的。
因为一个成熟的开源项目,都是几十个人用了很多年的时间慢慢积累的,你一个人想一下子就全部搞懂所有代码,这是不现实的。而如果你把时间浪费在这个地方,用来提升其他更有用的技术的时间就没有了。
### 如何判断学习深度?
所以说,就算是同一个基础技术,不同的技术人员学习的深度也是不同的。核心的原则还是之前提到的“工作相关”,根据工作内容来决定基础技术的学习深度。
下面,我举几个常见的例子来说明。
**1. 数据结构和算法**
对于绝大部分开发人员来说,主要是熟悉数据结构和算法的原理、优缺点与应用场景,还有自己所用的编程语言提供的算法和数据结构。
而对于中间件开发的技术人员来说,在做极致的性能优化的时候,Java的ConcurrentHashMap之类的并发数据结构,就需要掌握算法的原理和代码实现细节了。
**2. 计算机网络**
对于绝大部分开发人员来说,能够熟练掌握抓包工具抓取TCP/IP包,并且能够看懂包信息,定位网络问题就行了。
而对于运维人员来说,抓包、路由协议、组网配置等就需要深入掌握了。
**3. 操作系统**
对于绝大部分开发人员来说,掌握基本的操作系统原理和概念,能够使用操作系统提供的工具来定位程序问题就行了。
而对于驱动开发、内核模块开发的技术人员来说,操作系统原理、实现机制和代码都需要深入掌握。
### 如何让理解更加深入?
明确学习深度之后,因为基础知识点比较多,看起来比较散,所以你可能学了很多知识,但是不知道它们之间的关联关系,理解不够全面和深入。
应对这个问题办法就是[第19讲](https://time.geekbang.org/column/article/331463)中介绍的“链式学习法”,通过领域分层将基础技术和顶层的实用技术关联起来,形成系统化的理解,这样能够理解得更深,记得更牢固。
### 基础积累会不会浪费?
看到这里,你可能会有疑问:判断基础能力范围和基础技术学习深度的原则都是“工作相关”,那么如果工作发生变化,岂不是很多基础技术的积累都白费了?
这里就要看所谓的“变”具体是怎么变。
如果是前后两个工作的领域基本一致,那么基础技术的积累基本上是可以通用的。比如我曾经从PHP服务端开发转为Java服务端开发,在数据结构和算法、计算机网络、数据库和操作系统方面的积累完全可以通用。
但如果前后两个工作领域差异很大,那么基础技术的积累确实可能无法通用。比如我的一位同事从Android开发转为服务端后台开发,虽然数据结构和算法、计算机网络可以通用,但是SQLite数据库和Android操作系统这些就不能通用了。
所以跨领域转岗一定要慎重,要转的话就尽早转,越晚损失越大。
## 我的实际经历
我刚去UC的时候,是用C/C++做中间件,对高性能和网络都有比较高的要求。于是我深入地学习了CPU和网络的一些基础知识,最典型的就是SMP架构的CPU 的False Sharing(伪共享)问题。
这个知识点理论上属于计算机组成原理,但是计算机组成原理一般只会写CPU有L1/L2/L3 Cache,很少提到多核CPU的的Cache Line(缓存行)对齐会导致False Sharing问题,并且对性能有很大影响。MySQL也被这个问题给坑过,而Disruptor的高性能则是采用padding避免了这个坑。
你看到这里,可能会急着想去看看我说的False Sharing到底是什么。别急,这个基础知识点在我后来负责业务开发的时候就没用了,因为接触不到这个深度。
但是做业务开发的时候,MySQL的索引原理和Elasticsearch的倒排索引这些基础理论就很有用了,因为你要设计合理的索引和存储方案。不过这个时候,你也不需要把B+ tree的数据结构写出来,只需要知道原理,就可以设计合理的索引和存储方案了。
## 小结
现在,我们回顾一下这一讲的重点。
1. 基础能力是指工作任务相关的基础能力,不是整个计算机技术的基础能力。基础不等于底层,不等于源码,也不等于不变。
1. 提升基础的第一步,就是使用技能图谱的方式,从工具、生态、容器和原理这4个维度细化基础能力的范围。
