作为程序员,找工作有时候似乎挺苦逼的。
说真的,让我去掉前面这句中“似乎”二字吧。就是苦逼!很多人都曾抱怨处在招聘的一方很糟糕——我们没有任何可靠的方式来甄别会写代码并且写得好的人。这的确是真的,我们这行在这方面做得很糟糕。即使是在最常见的开发者群体(美国人、男性、白人、较为年轻和中产背景)当中,我们的甄别能力也绝对是一败涂地,而当面对更广泛的人群时,我们只会干得更差。但我们不得不扩大范围,因为就算我们没有道德感,我们也面临着数量的问题,职位岗位比上述“精英”多,总共只有那么多美国中产二十多岁的白人男性,然后其中一半根本不会应聘你们只发股权的“支持Uber、23andme、推特、部落冲突的无人机运输”公司,因为他们正在你创业的星巴克马路对面的另一家星巴克成立自己的公司。另一方面称职并且想要技术岗位却没得到的女性、非白人、外国人数量简直太多了。
但是应聘的一方(我现在所在的一方)也很苦逼。招聘方遇到的困境,也恰恰是造成痛苦流程的原因。
教育很烂
我们尝试过的其中一个方法是看学历。但是我们根本不擅长在学校教人编程。涉及到计算机的课程,应该是数学系还是工程系的延伸,多数大学都决定不下来。结果他们最后弄出来的是诡异的融合,但其实两者都不是;或者他们在教编程,但是语言和技术已经落后现有规范好多年;又或者他们让学生死记算法列表及其复杂度,这会让学生误以为编程不过是死记硬背,然后成为一个能输出正确算法名字和伪代码的自动机。因为公司真正想找的是就是复读机,难道不是吗?直接开发一个数据结构的复读机,可能再加上一个排序算法的复读机,大概就能省下很多面试的时间。
我深信现有的教育方式及其缺陷,是造成我们听到的软件招聘恐怖故事的原因。拥有 CS 硕士学位,却似乎不能从一张白纸开始写代码的人,其实不差;更有可能是他们受到的教育轻视实际编程而注重理论。在邮件列表和论坛发布“请给我写好的代码”帖子的人,其实不差;更有可能他们受到的教育建基于背诵和应试。另外如果你从没读过著名物理学家费曼造访一所采用这个方法的大学的故事,我强烈推荐它。
那仍然是编程教学处在的阶段:我们知道自己需要程序员,而我们没有足够多的程序员来写代码,更别说教出更多的程序员,所以这种死记硬背的现象广泛存在,这是因为这已经是我们现在力所能及的范围。我们只是希望我们“教”出来的学生,会跑去看 Ruby on Rails 的教程,然后无意中看见 GitHub 的文档,然后从中神奇地学会真正的软件开发、架构和最佳规范。因为大家都明白,他们不可能在学校里学会这些。
与此同时另一方面,在我合作过的技术牛人当中,大多数根本没有软件工程和计算机科学的大学背景;很多人直到快上完学才第一次写代码( 不要脸的偏见:我直到快大学毕业才开始通常意义上的“编程”,我也是在毕业几年后才开始以此谋生)。很多真正厉害的人会被“计算机科学本科”这一条件过滤掉,这是招聘方不谨慎定下职位要求时会遇到的问题。即使招聘方费心加上“或拥有相当的经验”,他们甚至也还是被过滤掉,因为履历上的学位似乎就是招聘者和 HR 筛选推送给实际技术人员的求职者的第一条依据。
顺带一提,我有一个哲学学位。并不是炫耀,不过软件领域很多我认识并尊敬的非常厉害的人都有着相同的背景。
所以将学历作为筛选标准效果并不好;公司也很苦逼,因为拥有 CS 学位并不意味着一个人已经准备好坐下来写代码;准备好写代码的求职者也苦逼,因为没有 CS 学位仍然是个短板,而且为了学位回归学校四年并不轻松。而且每一飞秒都有五万个编程训练营/培训班被启动,从中出来的人拥有哲学系、文学系、神学系、历史系和现代 A 线诗歌符号学的学位,但是当他们经历了训练营后,他们大概至少能和计算机系的学生水平相当,因为 CS 的课程基本都很烂,而且主动加入编程训练营的人通常很聪明而且充满动力。而且如果他们能学会拆解 A 线诗歌,基本就能确认他们能用你的 JavaScript 框架写出一个 CRUD 应用程序,因为那个 JavaScript 框架上周才发布,所以根本没有多少人拥有超过一两天的 ReAngleBoneASS 实战经验。
编程面试很烂
由于学历不靠谱,另一个甄别会编程的人的方式是编程面试。求职者和公司内部的某人交谈(通常是电话或者视频聊天),并被要求写出解决问题的代码。如果你还保留着好奇心我就告诉你吧,我们不擅长用这个方式选出会编程的人。简单来说,此类面试并不靠谱,因为它们太短、太做作、太压迫。
详细一点来说:我认识多个顶级人才被他们绝对胜任的职位给拒了,就因为这种编程面试。我倾向于把它们看作“问个谜语”风潮的最新版,这个环节当年由于微软的实施而流行一时,因为每家公司都想像微软一样又大又成功。现在,人们听说谷歌会进行编程面试,并且看到Jeff Atwood 的 FizzBuzz 测试,而每家公司都想像谷歌一样又大又成功,并且与 Jeff Atwood 的招聘恐怖故事产生共鸣,所以现在所有人都在进行编程面试。但是这种面试依旧很烂。可能这是因为谷歌据说用的是白板,而其他公司用的是电话。
想不想看一个非常称职却因为编程面试而被拒绝的一个例子?他被拒是因为面试官在电话那头笔录错了他念的 Bash 脚本,这当然让脚本出了问题。我绝对没有开玩笑或者夸张,而除了“神经病”我实在找不到其他形容。如果用的是白板,他就被录取了。
事实上,我十分确定我搞砸过一次编程面试(至少我到现在还没收到该公司的答复)。要记住我并不是刚毕业入行的人。我已经有超过十年的 Web 应用开发经验,处理过各种各样的规模系统;我是一个非常重要的 Web 框架的核心团队成员,并且可能是这方面的世界级专家;我真的写了关于使用该框架的书(最早的几本之一),有时会被聘请去教这个框架,以及被学术会议邀请去做关于这个框架的 keynote 演讲。我曾经有一阵子没怎么睡觉,全程死死盯着一个正在运行的程序,想要理清 Django 的旧式系统,发现我的精神动物是一只迟缓的懒猴,而过了一阵子当我的意识像甘道夫那样重新塞进身体时,我提交了仅仅两行代码进行反击,解决了五个“深藏 Django 腹中”不同的 bug。我挺擅长这些的,如果你还没注意到的话我希望你记住这点咯。
我希望你注意到,因为我基本确信我最近搞砸了一次编程面试。
我不会提那家公司的名字,因为这跟本文无关。我也不会公布他们问的题目,因为那也同样无关。那个题目并没有 FizzBuzz 那么简单,但还是很简单,是我下意识就能提出好几种解决方式的那种问题。面试官否决了我偏好的方法(大概因为这个方法直接调用标准库的函数而无法展示我能手动解决),于是我换了另一个方式。而我从记忆中重新构筑这个方法的时候恰巧犯了一个小错误,因为我过于自信了并且想跟面试官聊其他的,于是我想着我都知道怎么只靠记忆完成这个解决方案了,为啥不赶紧水过这个题目,然后谈谈我真正在乎的事呢。
顺便一提,我出了一个小笔误,就是我给错误的循环变量加了值。单字母的变量名很糟糕,即使是在你为了敷衍面试官而写的傻瓜程序里;再说白一点,代码能跑起来,但是结果是错误的。
而当程序跑完然后吐出错误的结果时,我全部的自信都荡然无存,内心OS:“我的个天!为啥不对!我应该知道的呀”,然后我一边疯狂调试,一边尝试向面试官解释我的做法并且回答他们的问题,一边读代码、看结果、加 debug 语句来查看中间值,然后整个气氛是:「哦!提醒一下,这会决定你是否能得到心仪的工作,所以别有任何负担哦」。
所以虽然我修改好了,但是用了比正常更多的时间,这让我想到我是不是可能会变成 Atwood 风格的失败招聘故事的新事例。“没错,有个拥有十年经验的人,所谓‘专家’,通过了前两轮电面,结果他居然连这个超级简单的函数都不会写,还花了九牛二虎之力来找到自己的错误。用这题当过滤器真是爽歪歪!”
如果你曾经在一轮技术面试之后感觉糟糕,如果你曾经感觉你彻底失败,是个废物,不该获得任何职位,只想住到远离计算机、技术和那些让你产生这种情绪的招聘流程的话:我真希望我能说一切正在好转。我能说的是,你并不是一个人。我自身的傲慢和想要赶紧完事然后往下继续的不耐烦,是我在那次面试失败的主因。
但是那并不会让最终的结果容易接受,也大概不会让这种面试变成公司有力的工具;这些面试似乎就是因为它们自身的属性而无法避免地会挤走合格的候选人。也就是说:缺乏经验的应聘者更有可能缺乏自信而大脑一片空白;或者花费太多力气来想出惊艳面试官的奇招,以至于最终垂死挣扎,看着无能;而有经验的应聘者很可能(我就是)把这种面试看成烦人的形式主义,只想越快搞定越好(约时间进行编程面试的时候,我甚至还跟招聘方开玩笑说我至少能用六种语言写 FizzBuzz,所以他们就直接告诉我想要哪种吧),面试结果只会符合古希腊人教育我们对于过分自信的期望。
而作为应聘者/候选人,这种面试更是烂。压力太大和缺乏容错空间,总是会让人感觉身体不适。编程面试对精神的虐待也同样糟糕。这真的是一个简单的“来证明你会写 for 循环吧”的题目吗?还是说这是一道藏着面试官想让你发现并阐述的深层问题的陷阱题?
这真的只是在考察基本的编程技巧吗?会不会有一些知名的算法或技巧,而你没有的 CS 学位早就会让你滚瓜烂熟,甚至能作为软件共济会的接头暗号?你是不是应该展示你精通这个语言和工具,还是说他们想你开口说出心中所想,来展示你可以好好分析这个问题?如果你能在 A 线诗歌里面藏头打出“FizzBuzz”,面试官会不会对你印象更好?
这些念头会全程萦绕在你的脑海。他们会使你麻痹,抽空你的自信和思考能力,然后让你看上去完全不胜任。但是 $大公司 就是这么干的,他们又大又有钱又成功,所以其他人也会跟着做,留下一片大脑麻痹、毫无自信、犹豫再三再四再七十四的僵尸程序员,他们只会语气平平大声喊“超出递归最大深度”,而那些公司只会全程抱怨为什么就是找不到人才,然后麻烦谁能清理一下这些僵尸吗?
一切都很烂
我曾多次处在招聘双方的处境,我也经历过这个欣欣向荣的软件行业的各个阶段的面试(我似乎平均每五年就要找一轮工作,这让我对各个阶段都有一些有趣的印象)。而我从中学到的只是我们干得太糟糕了。科学哲学(我在学校学过一点)有个很有名的“划界问题”:如何区分真正的科学,和那些用 看起来是正经科学的字眼 包装起来的伪科学。这个问题,至今仍没有什么灵丹妙药。
软件开发也面临着划界问题,但我们的问题有点不同:我们需要知道的不仅仅是谁已经会写代码,还要知道写得多好,而在那些还不会写的有志之士当中,他们还差多少,还需要多少帮助才能做到(换言之,不仅仅是“我们可以聘用谁”,还有“高低职位分别可以聘用谁”,以及“我们可以招哪个实习生然后给他推荐好的培训日后再聘用他”)。这边也没有灵丹妙药;如果存在的话,我们早就找到了,因为很多天才都花了大量的时间在寻找它。
至今为止,我发现有用的做法总会在其他时候失灵。那包含了审查 GitHub 或其他类似的东西来评估能力;用人际关系和介绍信来找出已经证明自己的人;用对话形式、交换人生故事的面试(也就是面试官和应聘者聊一些看过做过的事,还有他们解决问题的方式);编程面试;“关键词”面试(我参加过一次面试,目标真的就只是看应聘者有没有“说出关键词”,来看他们是不是真的熟悉这个领域);高压面试;低压面试;短合同观察期;实习生返聘计划;团队融入面试;结对编程;黑客马拉松;一对一面试;多对一面试;你再随便想一个吧,肯定被使用过了而且成功率最高只有一半。
因此这对雇主很不利。我应该提到过对应聘者来说也很烂了吧?太多流程都严重有失公允,然后由于面试官和应聘者立场上的鸿沟,这些流程更加糟糕。有时候你甚至不知道有人在评估你(特别是当流程第一环节就是 GitHub 主页筛选的时候),而且被找来主管技术/编程面试的人,经常把这看作一件浪费时间的苦差事,他们不会花时间准备,甚至不会了解一下应聘者,甚至不知道他们来面试什么岗位(我遭遇过好几次这样的情况,我敢说一个连应聘者的简历都懒得看的面试官,是不会让应聘者想要加入他们的)。除此之外,就算是最好的技术面试,也有很强的对抗性因素,这也特别让人不舒服。
但是作为应聘者,不在面试前恶补公司的技术结构,可能加上一些技术面经,包含排序、搜搜算法和怎么计算费米对芝加哥钢琴调音师人数的估计算法的复杂度。应聘者事先不做准备,那就太离谱了。因为就算面试官可以完全不了解应聘者和那个职位,应聘者必须做足功夫,说不定面试官真的会问调音师那道题。
我知道理论上这种非人性化和脱节,是太多人申请技术岗位的副作用;让流程人性化和处理所有申请,这两者不可兼得。但这肯定会让求职者充满苦涩。我真希望,我能感觉我是作为一个将要成为同事的人在接受面试,而不是由可替换齿轮 #7365 作为可替换齿轮 #9540 岗位的面试官,然后由于更多的可替换齿轮在排队面试而时间有限。而且如果你是最早的五千个齿轮,你只能获得股权。
这完全没考虑到人与人的差别,有些人擅长应对形式化的面试,而有些人并不擅长。(这两点都看不出,这个人会在真正的工作环境做得如何;如果看得出的话,那某种程度上,这些面试技巧可以用来申请我并不想要的那种职位。)
那我们该怎么做?
老实说,我根本不知道。技术招聘对各方来说都很烂,而且没有简单的解决方式。甚至都没有能让我们撑到解决方式出炉的权宜之计。不过我还是会提一些东西,只因为洋洋洒洒写 3,000 字吐槽却不提出建议,看上去太糟糕了。
一旦一家公司大到分离出专门的招聘团队或部门时,HR 就会变成应聘者和现有员工双方的痛点。我的意思是应聘者面对的很多招聘者,他们自己都只是刚刚找到工作。这就降低了他们的反应能力以及说服其他人这家公司值得加入的能力,拖慢了整个招聘流程。
如果你的招聘团队像旋转门一样很多人进进出出,你就该找出原因并解决问题,保证你放在那里的人真的了解公司,了解你在找的人才,别让任何一方(应聘者或需要信任的团队)空等。说的就是你,上次电话一个礼拜了都还没发送“招聘进度”邮件的某某公司。
当你依靠开发者进行面试时,请负责任地排好班。你已经在占用他们的时间,而且强迫他们切换注意力了;确保他们有足够的时间来不仅仅是打一个 30 分钟的电话,还要浏览应聘者的简历、GitHub 等,了解他们主管的职位的细节。跟一个能说出“我发现你做了/贡献了(项目)”并且能把这个项目跟公司和职位扯上关系的人交谈虽然只是一个小美好,但是小美好可以产生深远的影响。还有要确保面试官想要当面试官;我能判断出对方很明显只想面试赶紧结束然后回到“宏图大计”,这很糟糕。
别搞编程面试,如果可以的话,看看应聘者写过的代码,或者向他们描述你最近遇到的一个小 bug,然后问他们会怎么解决。如果你能相处跟职位相关的问题那就更好了。让应聘者选择在电话上解释,或者写下来发邮件给你。我认识一些能写出神级代码却没办法开口好好解释的人,我也认识擅长开口解释却害怕写哪怕只是零散代码的人;除非你的职位要求特别的演说/写作能力,不然就别偏向任何一边。
如果你必须进行编程面试,把用时和压力控制在合理的范围——你家的开发者都未必能在 30 分钟内在面对陌生人电话听写软件输出的情况下解决 bug,那就别强迫应聘者了。还有,你可以让讨厌面试的开发者改变心态:“这不是面试,是代码评估”。所有人都能把代码评估“电解”成 Agile™ 和 Lean® 等等的关键词。代码评估有开发者渴望的元素!
在所有这些之上最重要的是,请人性化一些。我们不是机器;我们只是让机器做有趣的事情。有时候我们甚至可以让它们做正确而有趣的事情。但我们终究是人类,而现在的招聘流程存在鸿沟般严重的人性化缺失。对人类人性化一些吧,其他所有事情都会轻松很多。