1. (一)
又是一个闷热的周六,灰霾就像粘在天空一样,依旧笼罩着这个城市。带着小宝,我们三人游荡在蓝色港湾的儿童城中,为小家伙的未来打算着。老婆和丈母 娘穿梭于一个又一个玩具店,而我,因为推着童车,不便走来走去,就带着小宝静静地欣赏楼下冰场里玩耍的孩子们。很快,我们的注意力就被冰场上两个正在进行 对抗训练的小男孩吸引住了。小宝快乐地随着冰球转动脖子,双眼紧紧地捕捉着黑色的冰球,不时发出愉悦的『喝彩』;而我,默默地看着两位『男子汉』一次次跌 倒,又一次次爬起,对抗虽然异常激烈,但任何一方都没有脏动作,这足以让真正的冰球赛场上的成年人汗颜。
连日来,对环法自行车赛兴奋剂丑闻的追踪报道,让曾经的英雄们纷纷落马。成人世界里,人们对于名利的渴望,对成功的追逐已经远远超出了能力或是道德 的底线。我们不得不承认,这个世界正变得越来越浮躁。会爬的恨不得立即会走,踉踉跄跄走着的,又恨不得能撒腿就跑。前两天我在卓越亚马逊上随便查了查『小 时学会』和『天学会』,结果发现分别有65条和157条结果之多。『Java程序设计24小时轻松掌握 』,『21天学会javascript』,『30天学会Visual C++』,...看着那列出的一大堆需要花很大力气学习和使用的语言,我不得不感慨这种浮躁已经无处不在。
小宝还在咯咯地乐。那种发自内心的,如雪花般洁净的快乐让我由衷地羡慕。如果不是上周日LP跟我严肃地讨论了一下在未来我如何更好地履行父亲的责任,此刻(周六的下午)我应该端坐在办公室里思考某段代码该如何去写,而不是在这样一个放松的环境下,任由我的思想翱翔。
我们讨论的结果是,一周里大礼拜我能不去公司工作就不去,并且工作日最好有两天赶在七点前回到家,这样,可以大大增加我在家中陪伴小宝的时间,提升 她对『父亲』这个角色的认知。在北京这样一个拥挤到几乎处于崩溃边缘的城市,以公司到我家长达三十五公里的距离来算,晚上七点前回到家就意味着至少提前两 个从公司出发,还得祈求一路上 1)没有事故(小概率事件),2)没有管制,3)没有幽灵堵车。两个小时的车程对很多北京人来说还在忍受的极限内,但对我来说,开车上/下班的时间超过一 小时我就已经浑身难受,更遑论两小时这一让人绝望的数字。所以,我决定在提前回家的那两天搭乘地铁,这样,只消花一个半小时,我就能回到家中;而且,在地
铁里,我可以暂时远离代码和互联网,翻几十页和技术毫不相干的书。巧的是,上周不开车的两天上下班时间里,我翻的书是《长日留痕》——一本我买了很久,翻 了几次却都没看进去的小说。史蒂文斯先生,书中的主人公,利用一次旅行的机会回顾了他漫长的管家生涯。在整部书中,他始终在回忆过去的人生,并且不断地探 讨一个严肃的问题:一位杰出的男管家究竟是什么样子的?
感谢这本书,让我开始严肃地回顾我自己的职业生涯。这思考断断续续游走了好几天,很多时候干脆藏身在潜意识中,以至于每每我工作累了,对着窗外中关村东路和成府路交叉的路口发呆时,它就会蹦出来,让我暂时从繁重的工作中解脱出来,在回忆中尽情徜徉。
2. (二)
教练一声哨响,把我暂时拉回。此时此刻,两个小家伙开始了一攻一守的对抗,场面也变得好玩起来——两个小愣头青从场地的两端以几乎相同的路线滑向中 圈,砰的一声,重重地撞到了一起,一同倒地。教练上前,把攻方的小家伙拉到一旁耳语几句,并比划了几下,随即恢复了比赛。两人从场地的两头快步冲向中圈, 守方将重心控制地很低,高速滑动中,目不转睛地盯着冰球。就在两人要接触的一刹那,攻方一个急停,然后迅速切向斜前方。由于扑得太猛,守方来不及调整,无 奈让攻方轻松绕过自己,打进一球。不知是看懂了比赛,还是单纯开心,小宝挥舞着双手,发出欢畅的尖叫声。
这就是教练的作用。他们告诉你什么是基本功,如何应对局势,以及一名优秀的球员应该具备什么素养。在一个人职业生涯的早期,一位好的导师比什么都重要。一晃我的程序员生涯已经过去了十年,在这十年里,我一直在不断探索一位优秀的程序员究竟该具备什么素养,如果当时有个教练能给予我指导,给予我探索的方向,那该多好啊。
可惜没有。软件行业没有教练,也没有拜师学艺的传统。也许曾经有,但自从程序员从手工艺人变成了工程师,教练或者师傅就不再重要。你基本不需要像手 工艺人那样具备从无到有做出点什么的技术,你需要的仅仅是解决某个或者某些特定问题的能力 —— 某种意义上说,这和流水线上的工人并无二异。这也导致了那些速成的图书的畅销,因为它们试图让你学习到的是如何完成任务,而非如何编程。当然,互联网正在粉碎这一切,程序员似乎又在回归手工艺人的传统,这很好。
虽然没有教练,但每个软件公司基本都会为新员工指定一名资深的同事提供『象征』意义上的 "mentor"。我说『象征意义』,并不是否定mentor的作用,而是说这些mentor并非职业化的mentor,『传道授业解惑』的为师之 道,mentor们勉强在解惑上提供了些许帮助。当然,对于公司来说,mentor最重要的作用是成为一个榜样(Role Model),通过他们的工作态度,工作习惯,工作能力,对新员工,尤其是处在职业生涯早期的员工产生潜移默化的影响。
我职业生涯起始的公司是神州数码网络公司(DCN)。如果将google或者twitter定义为『优秀』公司,那么,DCN显然处在平庸公司的行 列。好在DCN继承了老联想的底子,还有一批有理想的做系统的牛人。Z君就是这样一个人。碰巧我被分在了他所在的团队。当我把『一位优秀的程序员究竟该具 备什么素养』这样的问题抛给我的mentor,即将离职的X君时,他让我多看,多学Z君。之后,有意无意地,我都会多去劳烦Z君,他总会抛开手头的事,爽 快地为我答疑。为了解决某个问题,他经常工作到深夜;跟他讨论代码如果没揪到根上他绝不善罢甘休。拿code
review来说,当你看到一堆逻辑上无比正确但写作上WTF的代码时,即使想骂娘,但屈服于release的压力或人情世故,你总会妥协。但Z君不太会 妥协。他会笑眯眯地,毫不留情地指出你代码上十多处毛病,让你整改。很多人认为代码逻辑对了就足够,但Z君期待代码(算法)在时间空间上的合理(和谐), 以及是否做到了SoC。工作之外,他又是个吊儿郎当的人,经常爆发出的爽朗的笑声,浑身浓重的烟味,让你即使在很远的地方,也能感受到他独特的气场。
从Z君身上,我找到了一直追寻的问题的第一个答案:
真心喜爱你所做的事情。
真心喜爱你所做的事情。之所以斟酌出这个句子,是因为我觉得诸如『敬业』,『有韧劲』,『钻研』,『爱学习』等词语或多或少都被它涵盖,或者说,是它的自然而然的结果。
那时对我而言,『真心喜爱』就意味着每天超过12个小时泡在公司里努力搞明白遇见的每一个技术问题。很快,我搞透了OSPF,填补了X君走后OSPF上的空缺,之后又独立开发了IGMv3,SNTP,接着完成了极其重要的linux 2.4 kernel的移植。
3. (三)
由于工作的原因,我逐渐与另一个团队的S君打交道很多。S君兴趣很广,他帮着公司内部搭建了团队的wiki,使得信息的交流,知识的分享大大地系统 化。以前我们知识的交流以邮件为主,这很被动,当下有用的,还是无用的知识,都一股脑成了一封封亟待打开的邮件。打开看吧,浪费时间;不打开吧,以后需要 时都不知道自己的邮箱里还有这么份东西。在S君的推广和维护下,团队的wiki大大提高了大家获取知识的效率。
从S君那里得知,他使用了一个叫mediawiki(wikipedia使用的软件)的开源软件。我开始把玩mediawiki,进一步,我接触了 LAMP,并且逐渐意识到像linux,Mediawiki这样的开源软件的重要性。如果说林则徐魏源是近代中国开眼看世界的第一人,那么他也许是DCN 内部拥抱更广阔的世界的第一人。做system的,很少关注application的动向,有种天朝藐视番邦的傲娇;而做application的,则放 低姿态谦卑地注视着system的变化。现在随便拉一个做路由器的人,你问问他对web
application的看法,十有八九还停留在对LAMP的认知上;而做web application的人已经把触角伸向了user space data plane。究其原因,是做system越做越掌控一切,倾向于封闭;而做application越做越依赖生态圈,所以拥抱开放。
S君让我认识到了开源的力量和开放的社区的伟大之处。怀着对mediawiki的敬畏,我开始学习PHP,进而在他的影响下,学习据说是『聪明的程序员』使用的Python。我想我已经是『真正的程序员』了,如果能成为『聪明的程序员』,何乐而不为?
在这个过程中,我找到了第二个答案:
拥抱开源和自由软件,拥抱社区。
大学期间,我曾经是一个坚定的微软主义者:凡是微软推出的,我都拥护;凡是微软反对的,我都反对。直到毕业时,我还天真的认为C#就是我们这代程序 员的终极武器。S君及时把我从这种盲从中拉了出来,让我看到了一个不一样的世界。现在棱镜门事件的热度在渐渐褪去,但是,它让人们开始意识到 Richard Stallman的思想的重要性:开源软件关乎着人类的自由。遗憾的是(也许我不该这么评价),我的两任雇主,对开源软件的贡献要远小于其索取。
PHP和Python对于我所做的开发任务似乎毫无帮助,学习它们地目的是为了了解更广阔的世界,了解为什么最流行的软件会被用这样的语言开发出 来。为了更好的实践我的所学,我用PHP和Python做了一个工具:开发人员可以通过一个PHP撰写的web页面提交一项测试任务,后台的python 脚本拿到这个任务后会拉下指定版本的代码,编译,并将编译好的image传到直连的交换机上,然后开始运行测试团队提供的regression脚本。我的 工具带来的效率的提升引起了老板的重视,我被批准使用一台PC和两台交换机,组成一个完整的环境,供开发团队践行CI(Continuous
Integration)。
在这个过程中,我发现了第三个答案:
能够通过自身所掌握的技术,不断提高自己和团队的效率。
容我再解释两句。一个真正的程序员,在那些每天重复低效的干活方式展现在你面前时,很难抑制住利用自己的技能做点什么改变现状的心情。工作中(当然 生活中也是),这样的低效比比皆是。比如说从X系统中定期导出一些数据到excel中做报表,比如说一级一级收集weekly report进行工作汇总。
这种低效在我工作过的第二家公司,Juniper,也广泛存在。
回顾我目前的整个职业履历,我在DCN工作了两年零两个月,在Juniper China R&D(CNRD)工作了五年半,在途客圈作为创始人和CTO工作了两年,然后回到Juniper CNRD工作至今。所以,作为雇员,我总共就工作过两家公司,因此,是否每家软件公司都存在类似的低效,我不得而知。但我觉得,工作中的低效场景无处不 在,问题在于有没有被发现,发现后值不值得为此做点什么。
4. (四)
冰球场上的对抗结束了,小家伙们离场休息去了。我松开手上的童车腕带,把脑袋凑过去,轻唤小宝的名字。小宝显然还全神贯注于冰场,被我这突然的举动 吓了一跳。当她惶恐地转过头来看到是我,便放下心来,微微笑了笑,又回过头去欣赏冰场上的运动。循着她的目光,我看到冰场上一个也就六七岁大的小女孩一个 人在认真地练习花滑。她的动作如此纯熟,姿态那么优美,让你几乎忘了她的年龄。我想,她大概这么练了有很长一段时间了吧。
看到这里我不禁想起在Juniper曾经跟Y君讨论过我们招人的准则。我不解为何我们不给年轻员工,甚至应届毕业生一些机会。Y君认为我们需要的是 专家,而某个领域的专家,根据研究,需要经过10000个小时的培养。我算了一下,假使每周四十个小时,一年五十周扑在某个或者某些特定的领域,那么,五 年的时间就可以造就一个专家。这也是为何很多公司对于senior的职位,都要求至少五至七年的相关工作经验。但现实是,在面试中,很多五年,甚至十年工 作经验的人都未必对得起自己逝去的年华。我曾经遇见过一个工作了8年之久的程序员,在提供了vim,gcc等编辑编译环境的情况下,连一个非常简单的链表
操作的程序都无法正确完成。这是怎么回事?
我查了查"10,000 hour rule"的原文,是这么说的 —— "it takes approximately 10000 hours of deliberate practice to master a skill"。
问题出在了"deliberate practice"上。
何谓"deliberate practice"?钢琴考级有九个等级,每个等级都有要求的技法和曲谱。这是一系列刻意设计的练习,每一个级别都比上一个难度大一些,但经过努力还是可 以掌握的。当你对车尔尼驾轻就熟后,可以尝试一点巴赫,也许也可以是贝多芬,但绝不能倒着来,也不能跳着来。跳着来意味着你当前的水平和期望的结果之间的 鸿沟太大,也许已经超过了单凭努力就可以到达的境地。
可惜软件行业鲜有这样的"deliberate practice",学校和培训机构也没有类似的体系。所以这个社会能够批量造就钢琴9级获得者,却无法批量培养出合格的程序员。很多拥有五年工作经验的 人,折合成有效的经验,也许就只剩一年,剩下的四年只不过在重复自己第一年的收获。这就好比一个人掌握了车尔尼《钢琴简易练习曲》后,还在刻苦反复练习相 同的内容,即使练到脱离曲谱信手拈来,又有何用?
想想我们的境地,挺悲惨的。没有合适的导师指引方向,没有成型的体系来培养专家。但是我们还得不断地学习,不断地更新知识。对于那些还尚未『开窍』的程序员来说,职业生涯就像《富爸爸穷爸爸》所谓的老鼠赛跑,在蹉跎中耗尽光阴。
所以自我救赎的最好方法就是不断地给自己增加挑战,让自己脱离舒适区域。具体方法是:用那些刚好超过自己能力的任务挑战自己,build(尝试) - measure(分析) - learn(学习总结)。然后不断重复。这是lean startup一书中建议的精益创业模式,同样也适用于这个场合。
不要去看那些多少小时或者多少天就能掌握XYZ的书。生命苦短,多读读大师的著作和文章,他们能让你跨越到新的台阶;多写代码,多写能让你有征服感的代码。
这就是我找寻到的第四个答案:
不断跳出舒适区,有目的地挑战自己。
让我倍感欣慰的是,在Juniper的这五年半时间里,公司提供了各种机会让我在三个不同的team里学习和掌握data plane,kernel,以及application。托L君rellocate到US的福,我还有机会lead一支团队,来践行我在 leadership上所学的理论知识。
冰场里依旧人声鼎沸。怕寒气把小宝冻着,我不敢在此过度停留,我把车推着往里靠了靠,坐在一张椅子上稍稍休息。小宝举着双手似乎在抗议,但当她发现从她坐着的角度依旧能看到冰场的一角时,就渐渐安静下来,双手自然搭在童车的护栏上。
说来好笑,就在我离开Juniper的前夕,L君主持了一场小规模的英文演讲训练,以此来提高manager们用英文当众发言的能力。我的主题就 是"Move yourself out of comfort zone"。后来偶然的机会,我遇到了同样也离开Juniper的L君,他说他那时就感到我要离开。我问为什么。『因为CNRD对你而言已经成为一个 confort zone,你只需不犯错误,静静等待,就能一点点向上爬,而这又和你的性格,尤其是你的演讲传达出来的感觉不同。』L君回答道。
想想也真是。我的性格里流淌着不安分的血液,它源自我的父亲。一九九三年,父亲只身前往海南和广东,像那个时代的所有朝气蓬勃的年轻人一样,希望能 够在改革开放的最前沿,寻找工作机会,潇洒走一回。和其他人不同的是,父亲当时已接近不惑之年,有家有口,还捧着医生这样一个金饭碗。如今我已过而立,晋 升为爷爷的父亲年逾古稀,在这个本该安享天年的时刻,仍然奋斗在第一线,业余时间还以编者的身份出了个人的第一部书,同时正在紧张地编撰第二部。父亲就是 我的榜样,能够全面超越他是我的一大理想(当然这也是一个达尔文主义者必须做到的,总不能一代更比一代差吧^_^),可惜至今我还未能完成这一理想。
5. (五)
A language that doesn't affect the way you think about programming, is not worth knowing. - Alan Perlis
离开Juniper,我选择了创业,创建了途客圈。那是一段奇妙的旅程,一段让我成熟很多的征途。有史以来第一次,我写软件,不是为了我的雇主,我 的payroll,而是为了我的梦想。虽然这段旅程仅仅走了两年我就不得不因为一些个人的原因选择了自我放逐,但这两年,如乔帮主所言,是我开始去连接那 一个个"disconnected dots"。我的编程水平开始极大地发展,我的软件开发思想在不断走向成熟,我越来越觉得自己像是一个真正的程序员了。
重要的是,我开始学习新的语言了。你也许注意到,自从从DCN学习了PHP和Python后,在Juniper我就不再学习新的语言了,部分原因是 我在夯实我这两门语言的水平,尤其是Python的水平,但更关键的原因是我开始固步自封了。C让我成为真正的程序员,Python让我成为聪明的程序 员,我似乎找不到继续学习新语言的理由。
但是,创业改变了这一切。我不得不学习javascript,因为这是客户端唯一的标准。尽管在十多年前我就接触了javascript,并用它做 过一些效果,但那时对javascript的使用,与其说是使用,不如说是误用。在途客圈,我才真正重新认识这门prototype based language。另外,为了权衡究竟什么样的架构更利于未来的发展,我花了很多功夫深入了解ruby,在ruby和python之间进行对比。通过《松 本行弘的程序世界》,我了解了设计ruby时的很多思想。尽管途客圈最终选择了python/django,但这是一次非常有益的对比和思考,它让我进一
步找到了第五个答案:
学通超过一种编程语言,了解尽可能多的编程语言及其优劣,知道解决某个问题的可能的最佳路径。
注意学通和学会是两个概念。学会意味着你能够使用这门语言,会写程序,而学通则意味着更多:
- 了解语言被创建之出的动机,深刻理解语言背后的思想。
- 掌握如何在线调试(online debugging)和事后分析(coredump analysis)。
- 掌握语言外延/周边的技术。如JVM之于java,OS/CPU EABI之于C。
- 掌握如何提升关键代码的效率,如何能够扩充语言的能力。如NIF之于Erlang。
很多在简历中号称精通C的人不知道malloc背后都发生了什么,精通Python的人却无法用meta programming写出干净漂亮的代码。这样的精通其实也就是勉强学会。
按照这个标准,摸爬滚打了十年后,我在C语言上勉强算学通,Python和Javascript只能说学会,Erlang/Ruby刚算了解。
容我再解释一下为何要了解尽可能多的编程语言极其优劣。比如说新开发的软件并发模式要采用STM(Software Transactional Memory),如果在技术选型前,你知道clojure在语言层面,haskell在GHC层面实现了STM,那么,你的选择可能不会局限于你之前所用 的语言。
6. (六)
总而言之,现在完全不可能让时钟倒转了。你不能永远总是对过去也许会发生的事耿耿于怀。你应该认识到你与大多数人一样地过得很好,或许还要好得多,那就应该心满意足了。 - 《长日留痕》
Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgment difficult. - Hippocrates
也许是之前的凝视耗费了太多的精力,小宝开始打着哈欠揉眼睛。她回过头来,张开双臂,满眼期待地望着我。我知道,小家伙想要抱抱了。
十年前我根本无法想象十年后我能如此幸运而又意外地拥有她,正如十年后我无法预料她会变成什么样子。我可以为我的职业生涯,还有她的人生 做"deliberate"的打算,但我无法控制结果。过去的十年,我遇到了很多很多十字路口。就像《长日留痕》里说的那样,『你不能永远总是对过去也许 会发生的事耿耿于怀』。重要的是,我做出了选择。我很高兴我的人生经历与大多数人一样丰富,或许还要丰富得多,我很高兴我有很多很多故事讲给我的孩子听。
哦,忘了说另外一个答案,也就是第六个 —— 当然,仅仅对非英语母语的人有效:
能用英文自如地阅读,写作和交流。
一位优秀的程序员究竟该具备什么素养?
在用了近8年的vim之后,我决定,尝试emacs。