阿里毕玄现身说法:程序员成长路线

5,126 阅读19分钟
原文链接: mp.weixin.qq.com

技术圈很多人都知道毕玄这个名字,他 2007 加入阿里,历经阿里电商 10 多年来的技术架构演进,打造了阿里重要的中间件 HSF 服务框架,设计并带领多团队实现了阿里电商异地多活架构。2011 年开始打造了阿里自研的容器及对资源利用率提升巨大的统一调度系统。做过淘宝平台架构部架构师、集团核心系统研发部资深技术专家、阿里中间件负责人。

和很多阿里技术人一样,花名满天下反而忘了真名。他叫林昊。我认识林昊很早了,那时候他还在研究 OSGi 技术,我恰好在 QCon 上做过一次 OSGi 的应用分享,后来就认识了,他还送了我一本自己的签名书,一转眼差不多十年过去了。前几天他丢给我一篇自己写的程序员成长路线,说老池你读者不少,看看这篇有没有价值。我花了十几分钟读完全文,酣畅淋漓。毕玄结合自己十几年在阿里摸爬滚打的实战经验,给出了一条程序员的成长路线。

如果你想成为一名优秀的程序员,这篇文章就是给你写的(我做了简单的润色和修改,加了些图缓解阅读疲劳)。

ps,毕玄学的是生物专业,最早写 asp,就会做增删改查,这个编程基础你看看是不是还不如你呢?

从业余程序员到职业程序员

程序员刚入行时,我觉得最重要的是把自己培养成职业的程序员,我的程序人生起步比同龄人都晚了很多,更不用说现在的年轻人了,我大学读的是生物专业,在上大学前基本算是完全没接触过计算机,军训的时候因为很无聊,我和室友每天跑去学校的机房玩,我现在还印象很深刻,我第一次走进机房的时候,别人问,你是要玩 windows,还是 dos,我那是完全的一抹黑,后来就只记得在机房一堆人都是在练习盲打,军训完,盲打倒是练的差不多了,对计算机就这么产生了浓厚的兴趣,大一的时候都是玩组装机,捣鼓了一些,对计算机的硬件有了那么一些了解。

到大二后,买了一些书开始学习当时最火的网页三剑客,学会了手写 HTML、PS 的基本玩法之类的,课余、暑假也能开始给人做做网站什么的( ps: 那个时候做网站真的好赚钱),可能那样过了个一年左右,做静态的网页就不好赚钱了,也不好找实习工作,于是就开始学 asp,写些简单的 CRUD,做做留言板、论坛这些动态程序,应该算是在这个阶段接触编程了。

毕业后加入了深圳的一家做政府行业软件的公司,一个非常靠谱和给我空间的 Leader,使得自己在那几年有了不错的成长,终于成了一个职业的程序员,通常来说,业余或半职业的程序员,多数是1个人,或者很小的一个团队一起开发,使得在开发流程、协作工具(例如 jira、cvs/svn/git 等)、测试上通常会有很大的欠缺,而职业的程序员在这方面则会专业很多,另外,通常,职业的程序员做的系统都要运行较长的时间,所以在可维护性上会特别注意,这点我是在加入阿里后理解更深的,一个运行10年的系统,和一个写来玩玩的系统显然是有非常大差别的。

这块自己感觉也很难讲清楚,只能说模模糊糊有个这样的概念,通常在有兴趣的基础上,从业余程序员跨越到成为职业程序员我觉得不会太难。

编程能力的成长

作为程序员,最重要的能力始终是编程能力,就我自己的感受而言,我觉得编程能力的成长主要有这么几个部分。

1、编程能力初级:会用

编程,首先都是从学习编程语言的基本知识学起的,不论是什么编程语言,有很多共同的基本知识,例如怎么写第一个 Hello World、if/while/for、变量等,因此我比较建议在刚刚开始学一门编程语言的时候,还是就看看编程语言自己的一些文档就好,而不要上来就去看一些高阶的书,我当年学 Java 的时候上来就看 Think in Java、Effective Java 之类的,真心好难懂。

除了看文档以外,编程是个超级实践的活,所以一定要多写代码,只有这样才能真正熟练起来,这也是为什么我还是觉得在面试的时候让面试者手写代码是很重要的,这个过程是非常容易判断写代码的熟悉程度的,很多人会说由于写代码都是高度依赖 IDE 的,导致手写很难,但我绝对相信写代码写了很多的人,手写一段不是太复杂的可运行的代码是不难的,即使像我这种三年多没写过代码的人,让我现在手写一段不太复杂的可运行的 Java 程序,还是没问题的,前面 N 年的写代码生涯使得很多东西已经深入骨髓了。

我觉得编程能力初级这个阶段对于大部分程序员来说都不会是问题,勤学苦练,是这个阶段的核心。

2、编程能力中级:会查和避免问题

除了初级要掌握的会熟练的使用编程语言去解决问题外,中级我觉得首先是提升查问题的能力。

在写代码的过程中,出问题是非常正常的,怎么去有效且高效的排查问题,是程序员群体中通常能感受到的大家在编程能力上最大的差距,解决问题能力强的基本很容易在程序员群体里得到很高的认可,在查问题的能力上,首先要掌握的是一些基本的调试技巧,好用的调试工具,就像在 Java 里 JDK 自带的 jstat、jmap、jinfo,不在JDK里的 mat、gperf、btrace 等,工欲善其事必先利其器,在查问题上是非常典型的,有些时候大家在查问题时的能力差距,有可能仅仅是因为别人比你多知道一个工具而已。

除了调试技巧和工具外,查问题的更高境界会和编程能力的高级阶段有非常大的关系,就是懂原理,一个懂原理的程序员在查问题的水平上是有明显差距的,我想很多的同学应该能感受到,有些时候查出问题的原因仅仅是因为有效的工具,知其然不知其所以然,我给很多阿里的同学培训过 Java 排查问题的方法,在这个培训里,我经常也会讲到查问题的能力的培养最主要的也是熟练,多尝试给自己写一些会出问题的程序,多积极的看别人是怎么查问题的,多积极的去参与排查问题,很多最后查问题能力强的人多数仅仅是因为“无他,但手熟尔”。

就像我自己,排查问题能力的提升主要是在 2009 年和 2010 年,那两年作为淘宝消防队(处理各种问题和故障的虚拟团队)的成员处理了很多的故障和问题,当时消防队还有阿里最公认的技术大神多隆,向他学习到了很多排查问题的技巧,和他比,我排查问题的能力就是初级的那种,我印象最深刻的是有一次我们一起查一个应用 cpu us 高的问题,我们两定位到是一段代码在某种输入参数的时候会造成 cpu us 高的原因后,我能想到的继续查的方法是去生产环境抓输入参数,然后再用参数来本地 debug 看是什么原因,但多隆在看了一会那段代码后,给了我一个输入参数,我拿这个参数一运行,果然 cpu us 很高,哎,而且这种 case 不是一次两次,所以我经常和别人说,我是需要有问题场景才能排查出问题的,但多隆是完全有可能直接看代码就能看出问题的,这是本质的差距。

除了查问题外,更厉害的程序员是在写代码的过程就会很好的去避免问题,大家最容易理解的就是在写代码时处理各种异常情况,但这里通常也是程序员们很大的差距的地方,写一段正向逻辑的代码,大部分情况下即使有差距,也不会太大,但在怎么很好的处理这个过程中有可能出现的异常上,这个时候的功力差距会非常明显,很多时候一段代码里处理异常逻辑的部分都会超过正常逻辑的代码量,我经常说,一个优秀程序员和普通程序员的差距,很多时候压根就不需要看什么满天飞的架构图,而只用 show 一小段的代码就可以。

举一个小例子大家感受下,当年有一个严重故障,最后查出的原因是输入的参数里有一个是数组,把这个数组里的值作为参数去查数据库,结果前面输入了一个很大的数组,导致从数据库查了大量的数据,内存溢出了。很多程序员现在看都会明白对入参、出参的保护 check,但类似这样的 case 在我自己排查问题的经历里真的碰到了好多。

在中级这个阶段,我会推荐大家尽可能的多刻意的去培养下自己这两个方面的能力,成为一个能写出高质量代码、有效排查问题的优秀程序员。

3、编程能力高级:懂高级API和原理

就我自己的经历而言,我是在写了多年的 Java 代码后,才开始真正更细致的学习和掌握 Java 的一些更高级的 API,我相信多数 Java 程序员也是如此,我算是从 2003 年开始用 Java 写商业系统的代码,但直到在 2007 年加入淘宝后,才开始非常认真的学习 Java 的 IO 通信、并发这些部分的 API,尽管以前也学过也写过一些这样的代码,但完全就是皮毛。

当然,这些通常来说有很大部分的原因会是工作的相关性,多数的写业务系统的程序员基本就不需要用到这些,所以导致会很难懂这些相对高级一些的 API,但这些 API 对真正的理解一门编程语言至关重要。

如何学习呢?在没有场景的情况下,只能靠自己去创造场景学习,我觉得只要有足够的兴趣,这个问题还是不大的,毕竟现在有各种开源,这些可以很好的帮助自己创造机会学习。例如学 Java NIO,可以自己基于 NIO 包一个框架,然后对比 Netty,看看哪些写的是不如 Netty 的,这样会有助于你理解技术背后的本质。

在学习高级 API 和排查问题的过程中,我自己越来越明白懂编程语言的运行原理是非常重要的。我后面就开始学习 Java 的编译机制、内存管理、线程机制等,对于我这种非科班出身的程序员,学这些会因为缺乏基础变得很难,但这些原理性的东西学会了后,对自己的编程能力会有质的提升,包括以后学习其他编程语言的能力。

学原理最好的方法是先看一些相关知识的图书,然后去翻看源码,这样才能真正掌握,然后持续练习。以后在写代码查问题的过程中多结合掌握的原理,才能做到 N 年后也不会忘记。

池老师他们做的极客时间上有很多基础性和原理性的课程,都是技术大牛总结和梳理的知识,非常值得一读,读完这些精华专栏再去看源代码或啃大部头,会轻松很多。我们那时候可没这个福利。

在编程能力的成长上没什么捷径,我很赞同 1 万小时理论,在中级、高级阶段如果有人指点,或者与优秀的程序员们共事,会好很多。不过,我觉得这个和读书也有点像,到了一定阶段后(例如高中),天分会成为最重要的分水岭。到了极限,就很难再有突破了。

不过,就像大部分行业一样,大部分人都没到拼天分的时候,只需要拼勤奋就好。

4、系统设计能力的成长

除了少数程序员会进入精深的领域,例如 Linux Kernel、JVM 等,其他多数的程序员除了编程能力的成长外,也会越来越需要系统设计能力。

通常一个编程能力不错的程序员,在一定阶段后就会承担一个模块的工作,进而负责一个子系统、系统、跨多领域的更大系统等。

我自己在工作的第三年开始承担一个流程引擎的设计和实现工作,算是一个不算小的系统,而且也是当时那个项目里的核心部分。那个阶段我学会了一些系统设计的基本知识,例如需要想清楚整个系统的目标、模块的划分和职责、关键的对象设计等,而不是上来就开始写代码,但那个时候由于我是一个人写整个系统,所以其实对设计的感觉并还没有那么强力的感觉。

在那之后的几年,我开始负责更多系统,但总体感觉好像在系统设计上的成长没那么多,直到有了阿里的经历,才敢说自己在系统设计上有了越来越多的体会。有一次我在阿里做内部分享,讲到我在系统设计能力方面的成长,主要是因为三段经历,负责专业领域系统的设计 -> 负责跨专业领域的专业系统设计 -> 负责阿里电商系统架构级改造的设计。

第一段经历,是我负责 HSF,HSF 是一个从 0 开始打造的系统,它主要是用来支撑服务化的框架,是个非常专业的系统,放在整个淘宝电商的大系统来看,它就是一个很小的子系统,这段经历里让我最深刻的有三点:

1、要设计好这种非常专业领域的系统,专业的知识深度是非常重要的我。在最早设计 HSF 的几个框的时候,没有想好服务消费者/提供者要怎么和现有框架结合,在设计负载均衡这个部分也反复了几次,这个主要是因为自己当时对这个领域掌握不深造成的。

2、太技术化。在 HSF 阶段,出于情怀,在其中一个版本里投入了非常大的精力去引进 OSGi 以及动态化,后来事实证明这是个非常非常错误的决定。从这点我才真正明白在设计系统时一定要想清楚目标,而最重要的目标是与公司发展阶段相结合。

3、可持续性。作为一个要在生产环境持续运行很多年的系统,如何让这个系统能够稳定高效的长时间运行,对设计阶段至关重要。这里举个最 low 的例子,我最早设计 HSF 协议的时候,协议头里竟然没有版本号,导致后来每次升级都特别复杂。再举个典型的例子是 HSF 在早期缺乏服务 Tracing 这方面的设计,导致后面重新设计的时候,全部落地花了几年的时间。又例如,HSF 早期缺乏 Filter Chain 的设计,导致很多扩展、定制化做起来非常不方便。

第二段经历,是做 T4。T4 是基于 LXC 技术的阿里容器,它和 HSF 不同的是,这是一个跨多领域的系统,包括了单机上的容器引擎、容器管理系统,容器管理系统对外提供 API,其他系统或用户通过这个来管理容器。这个系统发展过程也是各种犯错,犯错的主要原因也是因为领域掌握不深。在做 T4 的日子里,我学会最重要的是,怎么去设计这种跨多个专业领域的系统,怎么更好的划分模块职责,设计交互逻辑。这段经历让我有信心去做一些更大规模的系统。

第三段经历,是做阿里电商的异地多活,这对我来说是一个巨大的挑战,因为这是个巨型系统。尽管我以前做 HSF 的时候参与了淘宝电商 2.0 到 3.0 的重大技术改造,但大家都知道,参与和自己主导是有很大区别的,这个架构改造涉及到了阿里电商众多不同专业领域的技术团队,在这个阶段,我学会的主要是:

1、子系统职责划分,在这种超大技术方案中,很容易出现某些部分的职责重叠和冲突,这个时候怎么去划分子系统,就非常重要了。作为大架构师,要从团队的职责、团队的可持续性上去选择团队。

2、大架构师最主要的职责是控制系统风险,对于这种超大系统,一定是多个专业领域的架构师和大架构师共同设计,怎么确保在执行的过程中系统最重要的风险能够被控制住。这时我真正理解了系统设计原则,设计原则是用来确保各个子系统在设计时都会遵循和考虑的东西,而不是虚无缥缈的规定。例如在异地多活架构里,最重要的是如何控制数据风险,这个需要在原则里写上,最基本的原则是可以接受系统不可用,但也要保障数据一致。

以前我看过很多系统设计里的设计原则或泛泛而谈,或千篇一律,毫无价值。设计原则要切实体现了架构师对目标的理解(例如,开始时异地多活只是个概念,做到什么程度才叫做异地多活,这是需要持续解读的,也要确保在技术层面的设计上能够达到目标)。技术方案的选择原则,要确保同时体现在细节设计方案里,并据此执行。

3、考虑问题的全面性,像异地多活这种大架构改造,会涉及业务层面、各种基础技术层面、基础设施层面,它的执行节奏需要综合考虑人力投入、机器成本、基础设施布局诉求、稳定性控制等,这种复杂度会超过一个小系统或独立系统几个量级。

系统设计能力的成长,最重要的有两点:

第一,先在一两个技术领域做到专业,然后尽量扩大自己的知识广度,例如除了写代码之外。还应该知道系统是怎么部署的,部署到哪去了,部署的环境具体是怎么样的,和整个系统的关系是什么样的。像我自己,是在加入基础设施团队后才更加明白有些时候软件上做的一个决策,会导致基础设施上巨大的硬件、网络或机房的投入。有时候只需要在软件上做些调整就可以避免这些问题。做做研发,再做做运维会是很好的知识扩展方式。

第二,练习自己做 tradeoff 的能力,这个比较难,做t radeoff 这事需要综合考虑各种因素,但这也是所有的架构师最关键的职责。你可以回头反思下自己在做各种系统设计时做出的tradeoff是什么,这个最好是亲身经历,听一些有经验的架构师分享他们选择背后的逻辑也会很有帮助,尤其是如果恰好你也在同样的挑战阶段,光听最终的架构结果其实大多数时候帮助有限。

程序员金字塔

我认为程序员的价值关键体现在作品上,被打上作品标签是很大的荣幸。作品影响程度的大小决定了金字塔的层次,所以我会这么去理解程序员的金字塔。

塔尖:有世界级作品的塔中:有国民作品的塔基:有公司级作品的

没有作品的程序员,不是好程序员。没有产品代表作的创业者,不是好创业者。

当然,要打造一款作品,仅有上面的两点能力是不够的,作品里很重要的一点是对业务、技术趋势的判断。希望看到这篇文章的读者,都能有机会打造一款世界级的作品,为互联网和软件的发展做出贡献。

最后推荐下毕玄的公众号,他经常会分享自己的所思所想,推荐关注:

近期文章推荐:

2019 年最受欢迎的编程语言 并发编程三要素