俺的招聘经验[4]:通过笔试答题能看出啥?

  前两天,有好心的网友在博客和Google+留言,催促俺赶紧写招聘系列的下一帖。被这一提醒,猛然发现这个招聘系列已经中断半年之久。今天赶紧补上。按照原先的计划,本帖应该开始聊面试的话题,但俺觉得笔试的话题还缺了一块,今天就继续聊俺在笔试方面的经验。
  在前面的帖子,已经跟大伙儿聊了笔试和面试的优缺点以及这两者该如何搭配。考虑到很多网友比较健忘,再略微回顾一下。笔试的成本(这里指时间成本)比较低,所以应该安排在第一轮。通过笔试,至少要能淘汰掉80%以上的应聘者(还记得《无处不在的二八原理》吗)。这样一来,面试官才有足够的时间和精力,去筛选剩下的这些人。
  因此,笔试题目要有足够好的区分度——能够比较明显地体现出应聘者的差别。否则的话,笔试就起不到筛选的效果。
  俺出的(针对开发人员的)笔试题,大都只有问答题和程序题,没有选择题或填空题。因为选择题以及大多数的填空题都属于封闭性问题。封闭性问题不但区分度很差,还有诸多缺点(《开放性问题 vs 封闭性问题》一文已介绍过,此处不再啰嗦)。   为了让大伙儿有一个直观的认识,俺后面谈的话题,都会拿同一个例子来说事儿。这个例子就是:求质数。(质数也叫素数,小学数学就教过了,俺就不解释了)。为啥要拿这个例子捏?因为这是一个老掉牙的面试题目,貌似国内外很多软件公司的面试题都有它的身影。想必很多人对它都不陌生,俺就不必浪费口水多作解释了。
  说到思路和想法,俺发现不少招聘者在给笔试题打分的时候,都有一个毛病:”只看对错,不管其它”。其实,“思路和想法”往往比”对错”更重要——它可以反应出一个人的知识面、创造性等多种素质。而这些素质对于一个开发人员是很重要滴。一个富有idea的程序猿会有更多的发展前景;而一个缺乏idea的程序猿,则会逐渐沦为码农,只能做一些重复性的体力活。   举例说明:

  假如有两个应聘者A与B来做这道”求质数”的题目。A用最普通的”试除”来判断质数并且程序实现正确无误;B使用”筛法”来求质数(没听说过筛法的同学,请看”这里“的介绍),总体思路对头但程序有些小Bug。那么,俺会更看好B同学。为啥捏?

  假如B同学之前就听说过筛法,那说明此人数学的知识面应该比较广;如果B同学之前没听说过筛法,是自己独立想出来的,那这个人应该很有才。反之,用”试除”求质数的思路,太过于普通,小学生都能想到。

  顺便说一下:某CSDN网友居然在留言中说,求质数这道题没啥意义。这让俺情何以堪啊!所以,俺干脆又写了一篇《求质数算法的N种境界》,让大伙儿(尤其是菜鸟程序猿)瞧一瞧求质数有多深的奥妙。

  俺拿到应聘者的答卷时,总是先花几秒钟时间,粗略扫一眼程序题。因为从一个人写的代码,可以很容易地判断出:此人是否养成良好的编码习惯。在筛选程序猿的时候,俺宁可要那种虽然技能差但是习惯好的,也不要那种习惯差但是技能好的。因为”习惯”是一种很顽固的东西——很难通过培训加以改变的;而技能相对来说,比较容易通过培训加以提升。   关于编码的规范性,大致有如下几个方面:   比如:应该缩进的地方是否有缩进?该留空格或空行的地方,是否留出来?   假如某个应聘者写的程序,连最基本的”作用域缩进”都没有体现出来。那么,大致可以判定此人的基本素质很成问题。   比如:命名变量名的时候,是用无意义的单字母变量名,还是用具有可读性的英语单词。说到英语单词,顺便提一下:有些应聘者写的程序里,居然用拼音来命名,真是让人大跌眼镜。   前面2条,大多数人都会留意到。但是很多人都忽略了注释。   通过代码注释,可以看出代码作者的编码功底。新手写代码,要么不写注释,要么注释里尽写些废话,犹如画蛇添足;而优秀的程序猿写的注释言简意赅、恰到好处,有画龙点睛之妙。   和刚才提到的编码习惯类似,细心也是很难通过培训加以改变的。要看出应聘者是粗心还是细心,只需在面试题目中留一些隐蔽的陷阱即可。   俺在招聘”初级软件工程师”的笔试题中,也用了”求质数”这道题,题目是这样说的:

请实现一个函数,对于给定的整型参数 N,该函数能够打印出自然数中的头 N 个质数。

请大伙儿把题目仔细看喽!然后,大伙儿猜猜看,有多少人审题出错? 据俺保守估计,大概在95%以上!绝大多数的答题者,都把题目错误地理解成:

请实现一个函数,对于给定的整型参数 N,该函数能够打印出头 N 个自然数中的质数。

  列位看官扪心自问一下,你是不是也属于看错题目的那95%的人?   这两句话,只不过有3个字挪了一下位置,意义全然不同(再次感叹,汉语真是一门模糊的语言)。俺当初设计这道题目的时候,就是故意留个坑,但是没想到有这么多人掉坑里。   可能有同学认为严密性和细心是一回事,其实两者有点区别(当然,细心的人通常也比较严密;反之亦然)。对于软件工程师而言,严密性体现在:编写出的代码是否尽可能地考虑到各种非正常的情况。   一个严密的程序猿,写出来的代码自然也比较严密。严密的代码会带来两大好处:其一,代码的Bug率通常比较低;其二,代码通常比较安全,不易被入侵。关于Bug率,搞开发的应该都晓得;但是代码的安全性,貌似很多开发人员不太清楚。俺简单聊一下。   大概是在安全界混的时间比较长,俺对代码安全性的好处深有体会。大部分入侵者对某个软件系统(比如Web服务器,数据库服务器)的攻击,都是利用了软件代码中隐含的漏洞。而这些漏洞往往是因为编写代码的人考虑问题不严密而留下的安全隐患。   大伙儿不要误会,以为代码安全的问题很遥远,跟自己无关。其实这是一个很普遍的、跨行业的问题。无论是放在互联网上的网站、还是企业的内部系统,或者是大众化的桌面软件,都存在被入侵的风险。因此,编写安全的代码是每个程序猿都面临的问题。   说了这么多,就是想让各位明白,严密性的重要所在。那么,如何看出应聘者是否具有严密性捏?俺继续以”求质数”作为例子。   在”求质数”的题目中说了:函数参数N是一个整型。那么,一个严密的程序猿,会在函数开头,就检验该参数的有效性。一旦发现参数有问题(比如说,N为0或者N为负数),就给出相应的处理(比如,断言失败、抛出异常、等等)。因为在这个场景里面,N<=0 是没有意义的,而且有可能引发程序崩溃。   顺便说一下,要编写出足够健壮且不易被入侵的代码(行话叫做”防御性编程”),是很有讲究滴,称得上是门学问。如果有读者感兴趣,俺以后找个机会聊一聊。   最后,再稍微说一下条理性。在笔试中,不论是问答题还是程序题,都可以看出一个应聘者的条理性。   有条理的程序猿写出来的代码,层次清晰,条理分明——很易懂且看了很爽;反之,缺乏条理性的程序猿写出来的代码,就像一团乱麻——看起来很吃力且让人抓狂。   由于”条理性”大伙儿比较好理解,俺就不举例了。   从应聘者的笔试答题中,还能看出很多其它的信息。不过上述这几条,是俺认为比较重要而且也具有可操作性的。

  本系列的下一个帖子,俺来聊一下面试过程有哪些讲究?

回到本系列的目录