不久前,InfoQ官网一篇《华为面试改革:增加 90 分钟网上编程 30 分钟当面编程环节,充分考察实际动手编程能力》的文章,受到很多程序员的关注。对于程序员来说,现场编程测试可能是考核编程能力的最好方法,但是如果用人单位没有考虑清楚考核题目和考核标准,可能彼此都会浪费时间。今天这篇文章,是一位有着丰富招聘经验的作者,给出的他在现场编程面试程序员时候的一些经验,当然他也澄清了几个被求职者吐槽的问题。
Reddit上的编程分类内容有大约 200 万用户,其中大多数帖子只有很少的评论,热门一点儿的话题一般也就 100 到 200 条评论。但是如果你在上边搜索“面试”这样的关键词,你看到的热门帖子数可是超越想象。
许多开发人员对编程面试都感触颇深。上面所有的帖子都在哀叹:如今的趋势是将现场编程测试当成获得软件工作的必要条件了。但却从来没有一个人为这种编程面试做出一番辩护。
在今天的文章中,我想做的是:
为编程测试提出充分理由。
列举一些最好避免的常见做法。
解释为什么面试总是涉及毫无意义的算法谜题,而不是“真正的”编程。
我写这篇文章的原因,是因为在我的职业生涯中,我有过 300 多次面试别人的经历,并且设计了我当前雇主所使用的面试流程。我所雇佣的团队每天都要进行开发人员面试。一个好的招聘流程是有价值的,本文不是关于如何设计一个完整成熟流程的教程,只是提到了一些求职者在合理情况下非常讨厌的事情,对于聪明的雇主来说,会尽量去避免做这些事情。
首先说说我们如何在 R3 招聘。R3 为了建造一个受比特币启发的分布式开源数据库,我们正在世界各地招募技术人员。开发人员的面试过程一般包括以下内容:首先,阅读一段代码,要求面试者在大约 5 分钟的时间内,快速地发回对代码的评审意见;其次,是一个 30 - 60 分钟时长的视频聊天+共享屏幕面试,面试者可以从家中接入,在编辑器中进行编程,可以自选熟悉的编程语言,只要编程语言足够主流,面试官就能读懂;最后,邀请面试者到办公室与团队和高管进行面谈。
根据候选人的个人特质和具体的工作角色,编程测试有时还包括设计部分和“谈话”式问题,因为面试者的工作不仅仅只是编程。我们发现,这样的一个面试流程其实还是很科学的;而且,至少与其他一些招聘流程相比,这个流程还是相当轻量化的。
面试官应该避免什么
既然这样,让我们从尽量避免的面试风格开始谈起。
我不推荐某些公司采取以下做法:
“机器人面试”与自动化评估。没有人喜欢做面试官,所以你的团队经常会要你看是否能把面试工作外包出去。我们曾经对这种机器面试有一段非常短暂的体验,却发现其结果与人为主导的评估结果并不相符。更重要的是,邀请应聘者参加面试是对占用他们宝贵时间提出的礼貌要求,如果我们要求某人免费为公司奉献时间,而公司不做出对等的奉献,这是很不礼貌的。面试官花一个小时和你通电话,表明他们和重视自己的时间一样重视你的时间。用一个冷冰冰的web APP来实现自动化的“作业”会带来截然不同的结果。尤其是高级工程师,他们一定会拒绝接受这种面试。
白板面试。虽然很多年前这种做法是可以理解的,但现在笔记本电脑和屏幕共享无处不在,编写程序最自然的方法当然是使用编辑器、键盘、搜索引擎和编译器这些工具来辅助面试者。另外,视频电话面试允许应聘者在家里用自己熟悉的电脑和工具编程,这比让一个人站在一个小会议室里,用一支粗胖的马克笔在白板上写代码要好得多。
面试一整天。许多公司都希望对开发人员进行一整天的面试,这通常需要5到8次的单独面试。这使得那些已经有工作的开发人员很难参加一整套面试,而这些人可能正是你最想雇佣的。如果先进行远程面试,然后利用午休时间进行一些回访,可以让求职者避免请假,这意味着他们更有可能完成整个面试过程。我个人发现:8次较之2次面试反馈而言,并不能显著提高团队的招聘质量。
大规模的“作业”。虽然我们最近开始要求应聘者面试前做一个简单的的任务,但这个任务不需要编写任何代码,而且可以在几分钟内就完成。我听说有些公司要求应聘者在面试时间之外编写完整的、真实的程序。同样,这也是对面试者时间的不尊重,许多人会明确地提出拒绝。
慌忙中随意编造问题。问题设计并不容易,你希望候选人事先做好准备对吧?所以作为面试官,你也应该提前做好充分的准备。
修复一个真正的bug或实现一个真正的功能。这样做除了会带来明显的版权问题之外,这也并不是一个保证面试过程可重复执行的好办法,也并没有办法确保你在这个过程中观察到各种优秀的编程技巧,比如,特性的实现可能仅仅涉及复制/粘贴,对现有的代码做出一些细微的调整。这样的面试过程还假设,你在为Java代码库雇用Java开发人员,或者为Ruby代码库雇用Ruby开发人员,如果你只是想雇用熟练的开发人员,并让他们在工作中学习你的本地工具,那么这种类型的面试并不奏效。
这里我已经讨论了一些需要避免的事情,但是我们应该要求程序员在面试中进行现场编程的基本前提仍然是成立的。现在让我们来思考一下,尽管它并不受面试者欢迎,为什么仍然是一个如此普遍的需求?
许多候选人不喜欢接受编程测试。面试者常常觉得招聘流程设计得不好,这些带来了大量的错误否定,导致人们充满愤怒和怨气。愚蠢的面试流程阻碍了他们自我能力的展现,因为这样的原因错过了一份工作,没人会为之高兴。
你自己觉得能胜任一份工作,却被面试拒之门外,这是一种糟糕的经历,尤其是当这个招聘流程貌似含蓄地宣称其科学、准确时。
因此,雇主们似乎可以不这样做,而是依靠更传统的面试形式,比如在面试中谈谈过去的从业经历。然而,多年来,编程测试这样的形式已经从微软等公司流传开来,几乎成了所有地方的行业标准。现在,很少有软件公司愿意只是进行一次友好的电话交谈就敲定录取。这是为什么呢?
编程测试是必要的
看着实习生带着心理阴影走出他们人生第一次编程面试,总令人感到那么”享受“。他们走出来时,先是带着一种呆滞的眼神,略带震惊的表情。然后,开始咆哮。
这些应聘者是如何开始先用一种编程语言编写代码,然后又觉得实际上他们并不熟悉这种语言,应该从头开始用另一种编程语言呢?一个简历上有 10 年工作经验的人,怎么就做不到在自己的编辑器中开始一个新项目呢?面试者怎么可能花 30 分钟试图生成一个随机数却仍然以失败告终呢?这真是太疯狂了!
老人们咯咯窃笑着,十分享受这个古老的入会仪式。“啊,这并不疯狂。让我告诉你大约要花多少时间……”
20 世纪 90 年代,微软在科技行业推广了结构化面试,这一面试过程以刁钻的脑筋急转弯式智力题而闻名,比如著名的“为什么井盖是圆的?” 还有一些编程难题,比如“在白板上用 C 语言对一个链表进行反转”。支持这种面试形式的文章是 Joel Spolsky 的经典著作《游击队面试指南》(Guerilla Guide to interview)。当这本书在 2000 年出版时,很快就被创业公司大量采用,比如一家刚成立两年的小公司,谷歌。
在一次采访中,Joel Spolsky 回顾了他向世界输出的源自微软的面试趋势。从当时的非结构化的面试出发,这是一个很大的进步,但如今他已不再满意于此。遗憾的是,他提出的替代方案是让公司只从实习生中雇佣正式员工。
但是我认为这项面试技术最著名的例子是Imran Gohry的FizzBuzz问题,2007 年 Jeff Atwood 的一篇博文“为什么程序员不能编程?” 引起了公众的注意。Jeff 在他的博客中写道:
每个人都是从头学起的。但令我感到不安和震惊的是,任何所谓的”程序员“都要找一份工作,但其中有些人却不能编写最简单的程序。这对任何以编写软件为生的人来说,都是一记响亮的耳光。
Dan Kegel 是我在谷歌和 Wine 项目中,一位受人尊敬的前同事。2006 年,他在谈到招聘开发人员时,曾这样说:
令人惊讶的是,在要求执行基本编程任务的面试中,有很大一部分求职者都失败了,即使是那些拥有计算机科学硕士和博士学位的求职者也是如此。例如,我曾经亲自面试过一些应届毕业生,他们无法答出“如何写出一个从1到10的循环”或“十六进制中F后面的数是多少”?
在面试中识别那些急于证明自己优势的伪程序员,戳穿他们夸大其词或虚张声势的故事,似乎听起来是件美好的事情。但我告诉你,事实并非如此。每个组建开发团队的人,真的是每个人,都会开始习以为常,面试官总是在面试中遇到没有实际编程能力的人,即使“编程”已经很宽容。
人们普遍认为,企业进行编程测试,是因为这些公司里充斥着痴迷于算法的书呆子,他们都试图挑出知识尽可能渊博的候选人,希望公司成为下一个谷歌,事实并非如此。公司会进行编程测试,是因为他们遇到了很多候选人,他们的简历看起来都很不错,甚至能对计算机行业侃侃而谈,但在被要求编程时,实际上却无法写出程序。真的不夸张,一点程序都写不出来。
如果你是一名求职者,能够达到下列条件,已足够让你脱颖而出:
如果你声称自己懂一门编程语言,那就应该乐意在面试中使用它。我猜测,在简历中列出C++技能的求职者中,至少有50%的人在被问及C++技能时,拒绝用C++编写程序。
熟悉你的工具。如果你是Java开发人员,这意味着你知道如何在你所选择的IDE中创建一个新项目,编写一些代码,并运行它,然后定位程序所创建的任何输出。你还应该知道如何编写和运行测试,以及使用调试器。
如果面试官要求自带工具,那就带着平日所用的工具去面试吧。不要试图在面试过程中现场安装东西。
熟悉一些基本编程要素:比如集合、IO、字符串操作、循环、数据类型,等等。如果你是一个函数式程序员,那么你应该了解如何在适当的位置对列表进行实际修改。我就看到过Scala程序员100%都败在了一个肯定有着明确解决方案的问题上。
了解你将要尝试使用的语言。不要被语法或类型安全方面的常见错误搞迷糊了。
如果这些对你来说都很基本,那么欢迎来到程序员面试的世界。
编程测试之所以重要还有一个原因。那些经验丰富、技术娴熟的工程师,也就是你想要雇佣的那种人,也会意识到这个门槛问题,他们也不想在一个随便什么人都招的团队中工作。一个强大的招聘流程不仅是求职者给面试官留下深刻印象的机会,也是面试官给求职者留下深刻印象的机会。我遇到过的最棒的同事,都因为公司面试很难而吸引了他们。在效率和误判之间取得正确平衡,是构建软件公司艺术的一部分。
然而,从候选人的角度来看,大多数关于面试的恐怖故事并不是来自那些第一关就失败的人。大多数对编程测试感到恼火的人之所以感到郁闷,是因为他们觉得自己被要求解决一些复杂而却不具有代表性的奇怪问题。
为什么总是出算法题?
面试中,最常见的就是要求编写自行实现的排序函数,反转二叉树,或者做一个图表搜索。
求职面试就像被直接送回大学学习一样。这么多年所有编写实际程序的经验突然被扔出窗外,你就像又回到课堂上,你被要求证明自己对理论课题的精通,而实际上那些喜欢啃 Donald Knuth《计算机程序艺术》的程序员总是能先你一步作答。
对于这种情况,当我阅读网上的讨论时,遇到的最常见的解释是雇主是白痴。第二种最常见的解释是,雇主都想成为谷歌,而谷歌显然需要计算机科学专家,而其他公司并不需要。但不管怎样,这些雇主还是非常推崇谷歌的招聘流程,希望让自己成为亿万富翁。
而真正的解释其实相当平淡乏味。当你坐下来为开发人员编写一个面试问题时,必须满足许多限制条件才能设计出一个好的问题。而满足所有这些约束条件的问题,往往看起来就是“算法类”问题。
这样的问题是恰当的。面试的目的是尽可能快地提取候选人的信息,并没有要求一个好的面试问题必须代表真实的日常工作。为了说清楚这一点,可以想想怎么面试飞行员。在建立了基本的诚意之后,可以在面试中询问候选人在各种紧急情况下应该做什么,这样的问题是合理的。紧急情况虽然不能代表日常飞行工作,但安全特别重要,所以没有人会指责面试官问了一些不相干的问题。然而,这种指责在软件世界中却总是随处可见。
既然我们的目标是尽可能快地提取求职者的技能信息,那么我们的限制条件是什么呢?
首先,要完成的程序需要非常短小。除非你想把整个面试时间只花在一个问题上,否则,一个有能力的开发人员在理想状态下,应该在 30 分钟左右完成这个程序题。而 30 分钟里写不了太多代码,这个约束已经淘汰了大多数可能提供实用价值的“真实”程序。
其次,它需要面试者独立完成,不需要复杂设置或特定环境的知识。在面试中每多花一秒在解释问题,就少花一秒去观察候选人展示自己的技能。有时我在网上看到这样的评论:“Foo 公司做 bog 标准的商业 web APP,所以他们面试时为什么不让我做一个 REST API,而是让我自行实现一个排序函数呢?” 但是,请尝试着写下一个“编写 REST API”的问题来甄选候选人,然后你会发现这个问题其实很大。这个 API 实际上实现了什么?数据从哪里来?希望面试者连接到数据库,还是从文件中提供数据,还是在内存中维护数据?诸如此类的问题。
理想情况下,一个面试问题应该可以在 30 秒或更短的时间内解释清楚。但有些公司确实会问这样的问题,如果他们只愿意雇佣有专门技能的人,即在他们所选择的特定框架下工作,并且该框架能够自动化生成所有的样板文件,那么他们用这样的问题来面试是可以的。在 R3,我们更愿意雇佣来自不同背景和专业的开发人员,所以我们必须坚持使用那些无需任何特定框架或技术,就能得出可靠答案的问题。
第三,实际上这些问题应该能让你相信候选人懂编程。编写一些返回一些虚假 HTML 的函数并不能解决这个问题。至少,你希望候选人能够运用循环、集合、类、IO,并且熟悉他们的标准库,当然我的意思是大致了解其中的内容,而不是牢牢记住每个 API。
第四,它应该给优秀的候选人一个脱颖而出的机会。我所提到的这些技能似乎都是非常基本的。这并不意味着这家公司的招聘标准很低。一个好的编程测试在问题上会设置足够的深度,从而让一个优秀的候选人可以迅速且令人印象深刻地创建一个比初学者更好的解决方案。有了足够的实践,面试官就能学会区分有经验的开发人员和初学者,即使他们向每个人提出相同的面试问题。
最后,你需要一些证据,证明候选人能够接受一个不会马上得出明显解决方案的问题,并通过自己的思考找到答案,而不是停滞不前。这个问题的确切性并不重要,重要的是它不能通过候选人盲目地匹配以前见过的东西来解决。这也是整个过程中最模糊的部分,对应聘者的思维能力进行测试到底意味着什么?它排除了“直接套用别人编的代码来做这件事”这种形式的大多数解决方案,尽管在实际工作中,这通常是正确的方法。
简短,容易解释清楚,只使用基本的语言特性,可能有糟糕的/优秀的解决方案,也不会流于套用样板。我认为,所有这些约束条件都是打造一个称职团队的基础,但试图满足这些要求,就不可避免地会导致面试者们遇到一些显然不具有代表性的算法难题。这些问题的目的,并不是要考察你是否真的记得那些你可能从未上过的计算机科学课程中晦涩难懂的算法。这只是找个理由让你编写包含大部分基础知识的代码罢了。
所以不要强调你的答案是否具有理想的计算复杂度,至少别在第一次尝试的时候做这样的事情,面试官可能并不在意复杂度。相反,应该把重点放在用快速和有效的方式编写干净的、没有 bug 的代码上。然后,如果你还有剩余的时间,可以再倒回去做进一步优化。
结论
由于缺乏全球认可的认证机构,以及对具体技术技能的需求,招聘开发人员的流程比某些行业要更加严格。从雇主的角度来看,这个流程在过去几年里有了很大的进步。对于那些乐于做这类面试的求职者来说,得到的奖励是能进入能力更均衡的团队,这样的团队中没有无用的伪程序员,而关于这点的抱怨,在过去相当常见,当然,在没有采用这种面试流程的组织中可能仍然如此。
尽管如此,我必须指出的是,无论我们在这个行业付出了多大的努力,招聘在很大程度上仍有随机性。精心设计的面试流程总是比随机面试稍微好一点,这就是为什么我们要这样去设计面试流程。但考虑到解雇不合格员工的高昂成本,而且人们总是对误判中的否定比肯定抱有更大偏见,因此,很可能会一直存在这样的恐怖故事:在一家公司,本来明显可以取得成功的候选人,却遭到了机械程序的拒绝。正如 Spolsky 提出的用实习代替面试的建议所显示的那样,尽管存在种种缺陷,但这种制度仍然难以克服。
查看英文原文:
https://blog.plan99.net/in-defence-of-the-technical-interview-966f54a58927
评论