You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
14 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 13 | 特别放送:选择比努力更重要
你好,我是四火。
又到了一章的末尾,特别放送时间。专栏上线后的这几周,我在留言区回答了一些问题,有一些是技术上的问题,也有一些是非技术上的问题。尽管在 [\[开篇词\]](https://time.geekbang.org/column/article/134212) 和 [\[学习路径\]](https://time.geekbang.org/column/article/134216) 中我已经介绍了全栈工程师的角色、重要性和学习方法,但是依然见到不少困惑和疑问,**其中一个问题反复出现,那就是面对那么多的软件技术,总有一种“学不过来”的感觉,为此感到焦虑和担忧**。尤其是对于全栈工程师而言,这个话题更是被放大了。
颇为遗憾的是,这几年来,我见到了一些相当有经验的做着 Web 全栈开发的程序员,他们还依然走在一条埋头苦干,不断堆积知识,单纯靠量取胜的路上。可是,我认为,学习是需要选择的,并且,选择比努力更重要。
今天的特别放送,我就来聊一聊,我是怎么认识这个问题的,希望能给你带来一点参考意义。
## 两个小故事
第一个故事,微软的测试团队改革。陆奇是一个程序员从技术做起,进而翻身的典范。最初他入职雅虎的时候只是一个普通的工程师,十多年后 ,他以执行副总裁的身份,不但牵头打造了 Bing 搜索,还完成了几项意义深远的改革,其中一项,就是合并开发和测试这两个原本独立的部门,大幅裁剪专职测试人员,让工程师做更多的事。
这样一来,有一些擅长使用内部测试工具进行测试的工程师,就慢慢丢掉工作了,原因很简单,他们更多的只是熟练工,而缺乏技术上的竞争力。**听起来,这似乎是微软内部组织架构变动和工具、技术栈封闭的锅**。
其实,合并开发和测试团队,对于许多软件公司,特别是互联网公司来说,是一个基本不需要讨论的事情。除了一些面向互联网用户的、交互较为复杂的团队,还配有专职测试(即便是这样的测试,为了节省成本,也常常外包给合同工去做了),绝大多数团队,都已经变成了软件工程师一肩挑的局面了,而测试只是被合并的一部分专职角色,其实还有线上运维等等。对于大型互联网企业来说,一个事实就是,工程师的全面性越来越强,这是一个不可辩驳的趋势。
第二个故事,是我在几个月前,参与面试一位有着超过 15 年 Web 开发经验的工程师,这件事就发生在五轮面试之后的讨论会上(这里涉及到的面试流程我曾在 [\[第06 讲\]](https://time.geekbang.org/column/article/139370) 中介绍过)。
对于这样一个比较资深的工程师岗五个面试官在讨论会上产生了巨大的分歧。招聘经理也就是负责吃饭聊天那一轮面试的人反馈非常正面说此人经验丰富谈吐得当leadship 层面也没有问题Bartender技术负责人重点考察了项目经验和系统设计反馈也颇为不错经验丰富而且能够从很多角度去分析和思考问题可其余的三轮面试面试官反映却大相径庭主要问题出在白板代码部分总的来说代码生疏书写也缺乏条理其中有一轮都没有写完代码写完的两轮也是 bug 满地,问题频出。最后,在争论之后达成一致,可以通过,但是只能勉强给一个比预期职位级别低一级的 offer。
作为一个技术岗位的工程师,编码能力是一个硬指标,因此这也是照章办事,不得已而为之的。只不过,我们私下里讨论,应聘者很可能是有足够的编码技巧的,只不过有一段时间没有写代码了,确实有些可惜。但是,猜想也只是猜想而已。
其实,故事有很多,但是这两个故事是我精心挑选的。二者分别对应的启发是,工程师在技术学习的时候,需要遵循的两个主要思路。
* 第一,技术是分级的,具体说,是分短命和长寿的,也是分表面和本质的。我们要学习各种技术,但是我们要把足够的精力放到长寿的技术以及技术本质上。这就是第一个故事带来的启发。
* 第二,基础知识和能力的训练需要长期坚持,无论是在工作中,还是工作以外。这就是第二个故事带来的启发。
## 技术的分级
下面我展开来讲第一个思路,技术分级。
我们都听过“技术无贵贱”的说法,但这并不代表我们要“无区别”地学习技术。工程师,说白了最重要的就是“工程能力”,就是应用工程化的思想和技术,去解决实际的问题。我把工程能力粗略地分成这样四个级别,请注意,**它们都必不可少**,这个分级也不严密,但是我们能从中看到一个大致的趋势:
![](https://static001.geekbang.org/resource/image/12/e4/12471848fea52f2c04ef7f676bab62e4.png)
* 比如说,稳定性上,从左到右逐渐降低,越靠右往往寿命越短。
* 比如说,学习难度上,不一定,但是总体来说从左到右逐渐降低。
* 比如说,针对性上,往往从左到右逐渐增加,即越往右就越是针对具体的问题。
下面我来具体说说图中的这几种能力。
软能力,比如我们对程序员要求最多的沟通能力、学习能力和抽象能力。哪怕再过几十年,这部分基本也是不会变的。
模式和思想,比如分而治之的思想,模块化的思维,客户端/服务端模式。这部分也相当稳定,可能随着技术的革新,也会有一些以往不受重视的模式或思想被列为重点,举例来说,十年前,我们可能很少谈论分布式的思想。
语言和平台,比如 Java 语言JVM 平台。这部分其实变化就非常大了,有的语言已经几十年了,有的则是几年热度之后就消退了。普遍来说,语言平台要比语言本身稳定一些。
框架和库,这部分差异也非常大,但是总体来说,基本就是最短命的。如果要花费大量的时间和心血去深究某一个框架和库,那么你会希望它要么相当有代表性和典型意义,要么有足够长远的未来。
对于这几种能力,还有几点我要强调说明一下。
首先,请不要误解我的意思。每一级的能力都是有各自价值的,**我们在解决实际问题的时候,需要使用到每一级的技术**。举例来说,要设计实现一个网站,全栈工程师需要发挥沟通能力、合作能力,需要利用在模式和思想方面的经验和认识,选择合适的语言和平台,最后再选择相应的框架和库来完成它。
其次,我们当然希望图中靠左侧的“长寿”的能力得到进步,但每一级能力的培养,都需要通过对具体技术、业务的学习积累来实现,也就是说,**这些分级之间是不冲突的,反而是互相促进的**。通过这两章的学习,特别是从具体技术到通用模式这样的方式,也许你已经体会到了这一点。
那么现在,有了上面的说明,你是否已经清楚,该做出怎样的侧重了呢?
显然,我们应该明确的一点是,把几乎全部的精力都投入到这个分级的右端,换言之,**把大量的时间都花在记忆一个接一个的框架和库上面,妄图靠数量取胜,不可取**。有时更可悲的是,就连生硬的记忆本身也不讨好——都不用等到技术淘汰了,它们还都是公司内部的框架和库,离开公司就一文不值了。
因为,这只是单纯地记忆,没有比较、分析、思考这些能让这个分级均衡发展的行为。而这,我认为正是系统的技术学习中最大的误区。
我举一个真实的例子来说明这个现象,有位程序员朋友学习前端技术,最开始使用 Backbone.js后来陆续用过 AngularJS 以及 React现在准备转向 Vue.js。看起来似乎很勤奋但是他自己却说他依然只是停留在上头说用什么自己就跟着学什么的程度自己也没有什么想法总之越学越麻木……他自己还说“不知道何时是个头”。
接着,我想展开讲一下其它几个具体技术学习中的典型误区,而这些误区,在我看来也都和是否努力无关,本质上也都属于不恰当的“选择”。
**1\. 过于关注配置使用,忽略原理和场景分析。**
这一点我觉得是最容易在迈入职场没多久的程序员身上见到的问题,非常普遍。老板一个命令下来,心里慌得很,就想着怎么把问题搞定,而有一些问题是知识迷局一类的,比如,怎样配置整合 SSHStruts、Spring 和 Hibernate
这类问题光靠想是没法得出结论的,于是通过各种搜索、查文档、试错等等方式,花了很长时间,好不容易搞定了问题,完成了需求,又紧锣密鼓地去接下一个任务去了。**可是呢,对于刚才使用到的技术,付出了那么多,却只收获了这一个小小的迷局的解**。这投入产出比低不说,人还是很健忘的,这些具体的配置和使用,只要不用,很快就会忘掉的,下次在遇到类似的问题,可能已经忘记了这些配置,于是又要重复这一行为。
**2\. 过于关注编程语言的语法和语言技巧,忽略语言思考和书写时的思维模式。**
比如说JavaScript 语言,里面有很多坑,但是有一些坑是语言本身的不良设计造成的,知道当然好,但也不要因此沾沾自喜。但是对于一个写惯了 C++、Java 等后端静态语言的程序员来说JavaScript 异步编程、函数成为一等公民等等这些颠覆以往编程思维模式的特性,才是学习这门新语言一个收获颇丰的地方(我们会在下一章介绍)。换言之,我们要写 JavaScript就要写真正的 JavaScript——而不是写 Java再按字面翻译成 JavaScript。
**3\. 过于关注具体实现逻辑,忽略了对于设计的思考和权衡。**
我看到很多程序员朋友都热衷于研究源码,看完一个库,再看下一个,有些人甚至以读过源码的数量为荣,张口闭口就是“你读过多少源码”。
阅读源码当然是一件好事,但是请不要认为研究源码的目的只是“知道怎么实现”。毕竟,每个人的时间精力都是有限的,读源码尤其耗时。既然要读,就要读得有所收获,而不是凭空指望“读书百遍,其义自见”。比如说,阅读的时候,要抓住主干,去思考里面的设计思路,也就是所谓的“代码骨干”,忽略那些次要的边边角角。
**4\. 直接学习模式和思想,脱离了具体实践。**
我已经介绍了模式和思想学习的好处,但是对于那些抽象的理论和概念,在没有实践的基础上,是很难真正“消化吸收”的。最好的方法是动手做一做,如果时间有限,至少也要阅读和了解它们都被哪些具体技术采用怎样的方式实现了。
## 基础知识和能力
下面我来说说第二个思路,基础知识和能力。
即便在同一级的技术上,我们的学习也应该是有轻重缓急的。我们的项目中需要的技术,当然要学,但是我们心里需要清楚那些所谓的“基础”。生活不可能完美,工作也是,工作中学当然很好,但**很遗憾的是,有很多“基础”光靠工作中学是很难有较大进步的**。比方说,算法和数据结构。
我认为,数据结构、算法、网络等等这些,都是基础知识,如果工作中的强化不够,工作以外的学习和训练还是需要的。如果你的基础不够扎实,特别是“非科班”出身的话,它就更加重要了。比较好的一点是,这些相对于“设计能力”“问题解决能力”等等来说,还是要好学很多。
**除了基础知识,还有基础能力。最重要的,就是编程能力。**值得庆幸的是,我相信大部分程序员都会在工作中有足够的编程时间,因此,只要专注、带着思考去写代码,认真对待代码评审,编程能力是会随着经验的增加而逐渐提升的。
最后,你正在学习的这个专栏,涉及了大量的全栈技术相关的知识,但是从内容设计上你应该可以看出,我希望能更多地介绍其中的“套路”,也就是上图中的模式和思想,有些是同类技术所共同有的(比如前几讲介绍过的 IoC有些则是跨技术类型但却依然共有的比如幂等性和安全性
## 总结思考
今天的特别放送,我结合了自己的积累,介绍了我们该怎样做出选择,来应对这个“学不过来”的话题,特别是介绍了一些常见的学习误区,希望你能从我的答案中有所收获。
今天就不放特定的思考题了,因为我觉得,这一类主观性特别强的话题,很容易有不同的认识,不需要拿问题来引导思考方向了,不加限定地思考会更好。欢迎你在下面的留言区谈谈自己的看法,我们一起讨论。
## 扩展阅读
* 有一篇文章,[Stop Learning Frameworks](https://sizovs.net/2018/12/17/stop-learning-frameworks/),观点比较朴实,也比较偏激,在程序员群体内掀起了轩然大波,有朋友翻译了,译文在[这里](https://zhuanlan.zhihu.com/p/52814937)。
* 关于传统关系数据库技术淘汰的事情,以前我写过一点小[体会](https://www.raychase.net/3689),可供参考。