财新传媒
位置:博客 > 万战勇 > 【老万】以码鉴人

【老万】以码鉴人

前一阵,在中学同学群里,黄律师又晒他们律师行年会的照片。俊男美女一排排,肤白貌美气质佳,看得我鼻血横飞。

为毛律师都身材这么好呢?黄律师说,这是因为他们做的是一份要见人的工作。哦,合着我们码工干的是见不得人的事啊!都是出来卖的,凭啥要有高低贵贱美丑之分?

但我得承认,黄律师话锋犀利,一语中的,不愧是庭辩惯了的。码工们绝大多数不直接跟客户打交道,他们的光(wei)辉(suo)形象也不会像董明珠小姐一样占据开机画面。用户不关心他们用的软件是谁写的。正如钱钟书所说,你吃了一个鸡蛋,觉得味道不错,不会想到要去会一会下这个蛋的母鸡。我们码工就是下蛋的鸡。

黄律师又说了,你们码工虽然不见人,但是你们用产品说话,纸里包不住火。以前手写信的时候,大家说字如其人。后来改打字了,又说见文如面。那么,是不是可以从一个人的代码来推断他的品行个性呢?

这真是一个发人深省的好问题,值北京三环内一套精装修房。以我在业界纵(da)横(gun)十数年阅人无数的经验看,以码鉴人是可行的。

据说世界上有两种科学:一种是科学,还有一种是计算机科学。虽然这是在黑我们 IT 业者,其实离事实不远。码工的工作,不能用科学的眼光去衡量。因为,很大程度上这还是一门艺术,跟说相声写段子本是同根生。解决同样的问题,一千个人可以有三千种写法。代码,确实能反映作者的个性。

一个风风火火雷厉风行的人,写出来的代码多半也是一日千里,一泻如注。从短期看,这种人效率很高,适合用在项目早期开天辟地抢占地盘。因为,不管是公司之间竞争也好,还是公司内部小组之间竞争也好,把东西做出来快速迭代是第一重要的。好代码和好文章一样,立意和设计固然要紧,最终还是靠改。同样的时间,你只写了一遍,别人已经改了三遍,那么别人的产品大概率会更加成熟,毛刺更少。何况,还有先发优势。

但是雷政富的问题是不能持久。一味图快,置隐患于不顾,到后期维护起来会很头疼,进一步退两步。这种方式,我把它叫做“击鼓传花”式开发。开发者最后自己都会失去信心,放弃彻底修正系统的努力,只希望系统不要在自己手里爆掉。至于不幸接手这个项目的同事下场如何,他们就顾不上了。你觉得,这样的项目会成功吗?

最低级的程序员,也就是菜鸟,写代码经常就事论事,专注于解决眼前的问题,没有看到更一般性的问题。他们的代码里面充斥各种不必要的假设。这样的代码虽然也能用,系统的需求稍微一变化,就要大改。这就是为什么低级程序员忙忙碌碌半天,好像做了很多事情,但最后出来的东西不多。因为他们做了很多重复的低级劳动。而且,这种抽象度不高的代码里面很容易隐藏 bugs。

再高级一点的程序员,会注意代码的效率、可重用性和可维护性。这时候,不只是要解决一个具体问题,还要讲一点逼格了。没有风度的代码是会被人笑话的。

最常见的以码鉴人场景,就是面试了。做为面试官,要在短短的几十分钟内,对候选人做出一个聘用与否的判断。为此,必须要从他们的回答中快速获取足够的高质量信号。这些年,经我面试的码工有几百人。我的经验是,不管他们应聘的是哪个级别的职位,一定要真刀实枪地测试程序员看家的本领:现场写代码。我见过太多的候选人,简历金光闪闪,谈起方法论头头是道,推荐人夸他们不遗余力,但写代码却顾左右而言他,码不达意。这种人,我坚决反对聘用。

我在面试时如何评估一个人的代码水平呢?

首先是正确性。就是说程序不能干错事,不要有大 bug。这是最基本的要求,初级程序员也必须做到。遗憾的是,很多人都过不了这一关,在这里就被刷掉了。我知道,面试时间短压力大,不容易做到程序 100% 没有 bug,但是起码要保证没有重大的设计漏洞。如果一个人的代码前后矛盾,逻辑混乱,我们可以推断他在工作上是靠不住的,因为他连把问题想清楚的基本能力都没有。这种人不适合做需要复杂推演能力的程序员。看门大爷或者是保洁大妈可能更适合他们的特长。

编程不是做证明题,光答案正确还不行。我们还关心答案的效率。中等层次的程序员,清楚程序执行的代价,知道怎样用较少的资源算出答案。这个资源,包括时间(算得要快)空间(少占存储器)和金钱(少用收费服务)。这个阶段的程序员,考虑问题比较周到,不犯大的逻辑错误,还熟记各种常用数据结构和算法的适用范围和时空复杂度。所以,他们可以根据设计需求灵活地选用合适的算法和数据结构。描述复杂度的大O-符号是他们的好朋友。

如果一个人的代码效率较高,也能清楚地解释他选择一个设计方案的理由,我们可以想象,他应该不是一个看问题片面,做事不计代价易走极端的人。现在申请美国签证都需要提供社交网络账号,理由是方便美国政府甄别恐怖分子。其实,如果申请人是程序员,看他们写的代码恐怕是更可靠的手段。

再高一层的程序员,要注意代码的鲁棒性、可读性、可维护性和可扩展性。鲁棒是一个音译词,来自英文 robust,不是山东棒子,也不是鲁迅牛逼。所谓鲁棒,就是说代码不能像林妹妹一样弱不禁风,要像鲁智深同志一样抗造。遇到不合预期的情景,要有倒拔垂杨柳的能力和拳打镇关西的勇气,绝对不能像武大郎稀里糊涂喝下潘金莲亲手熬制的毒药系统崩溃,或者是像司马懿被诸葛亮误导算出错误的结果,甚至干出删除原始数据格式化硬盘之类亲痛仇快的蠢事。

可读性和可维护性是不可分的。程序写一次,会读很多次。初级程序员想的是怎么写着方便,高级程序员关心的是怎么读起来容易。因为,在一段代码出生之后的漫长的岁月中,它会经历各种改写。如果改写的人不能领会代码原作者的良苦用心,很可能会引入新的逻辑错误。为了减少这种可能,代码必须写得一清二楚。想要做什么,那就写什么,不要给维护者打哑谜,考验他们的智商。

可扩展性也是一个重要指标。好的设计应该考虑到合理的需求变化,但也不要过度工程,把各种不太可能出现的情况都考虑进去——这样只能徒增复杂度。能把握好平衡,不过于简单也不过于复杂,再把格子衬衫换成潮服,那就是艺术家了。

谷歌大神姐夫丁曰:设计一个系统必然要针对某个特定规模的问题做优化。每天需要处理 10万次用户请求的系统,和每天要处理1000万次用户请求的系统,它们的架构肯定是不一样的。在做系统设计的时候,既要考虑到以后数据规模的扩大化,也不要过度设计。姐夫的原则是:一个好的设计应该可以容忍10倍的数据规模增长,但是不要再考虑多了——因为100倍的规模增长会需要一个完全不同的设计。

做到以上几点,就可以算一个优秀的程序员。再要提升,就到卓越的层次了。我的感受:从优秀到卓越,在编程技术上的差别不是那么显著,更重要的是其它维度的能力差别:卓越的程序员知道哪些问题是值得解决的,哪些是不值得花大力气的,他们也有足够的领导力带领团队去解决那些最值得的问题。

有人问,像我这样面试要求是否过于苛刻了?毕竟初出茅庐的学生经验不足,工作多年的老码工好多算法和数据结构又都忘了,对这两种情况是否应该网开一面?

对于素人,我的要求可以稍微降低一点,但是正确、高效的底线不能动摇。经验不足不是理由。现在计算机这么普及,各种公开课、开源项目鳞次栉比,只要用心,机会大把的是。这种情况下还缺乏基本的经验,只能说明自己热情不足或者是努力不够。公司不是解决就业率的慈善机构,能力不够的人不是我的兄弟,没有热情的人不是我的兄弟。

这样是不是会错过一些人才?我说,任何选拔制度都肯定会有遗珠之憾。我们的目的不是不计代价把所有的人才都一网打尽。蒋公说,宁可错杀一千,绝不放跑一个。招错了人,对团队的贡献是负数,代价惨痛。我宁愿保守一些。

至于说老程序员不记得数据结构,我看是对真正老程序员的侮辱。如果你工作多年一直从事的是初级的代码搬运工作,确实有可能把基础都还给了老师。但是,这样的工作经历是负分,这样的人不适合做程序员。真正热爱编程的高手,不管做到什么级别,只要还在程序员这个行当,基本功绝对不会丢。姐夫丁编程多少年了?现在还在每天写代码。你敢说他常用算法数据结构记不清了?如果说姐夫丁不是凡人没有可比性,我可以负责任地说我身边的老程序员一大把,大多数都相当犀利。

我上大学的时候,电脑还很稀罕。虽然是计算机系,我们上机的机会也不多。说出来你们不信:一周只有两三个小时可以摸到真正的电脑。这种情况下,很多编程作业是用纸笔完成的。我的第二门编程课是 Pascal。做作业时,我选变量名、大小写、缩进、拼写,一丝不苟。同学郭教授看了,质疑我这么做有何意义。

我义正辞严地指出:代码代表了作者的风度。我要对自己的风度负责。

推荐 12