程序员,请拒绝无聊的代码面试!

什么是“代码面试”?

 

“代码面试”指所有直接测试候选人的技能,或审查他们编写的代码或伪代码的方法。这些方法包括:

  • 审查代码片段,或GitHub的个人页面;

  • 编程测试(Codility等);

  • 编程挑战,或在个人时间里自由完成的题目;

  • 现场编程,或结对编程;

  • 在白板上实现算法。

 

 代码面试的目的

 

这些方法的出现绝非偶然,而是为了取代那些更差的面试手段,比如:

  • 脑筋急转弯:一架波音747中能装多少个网球?

  • 咬文嚼字:Java中接口和子类的区别是什么?

  • 白板编程:至少在这些中不是最差的......

  • 发现式测试:“怎样检测链表中是否存在环?”

我们认为,这一切都是非常愚蠢的面试手段,因为它们无法反映软件开发者在日常工作中所需的技能。因此,我们在面试过程中,试图通过代码面试重现日常的工作。

然而问题在于:这种方法也根本不管用。因为真相是:代码面试根本不能重现真实的工作。当然,代码面试能让候选人展示工作所需的部分技能——但代码面试的环境和真正的工作环境完全不同。

 

代码面试的问题

 

代码面试能减少候选人的数量,但也能拒绝真正优秀的候选人,还能对差的候选人做出虚假的判断。

代码测试会占用面试者和候选人双方大量的时间。如果能产生效果,也许前者还可以接受,但后者会导致很难在买方市场上寻找到好的工程师。

由于随时更新代码测试题很困难,结果就导致面试体验很差。如果候选人对现有的工作满意,那么他们根本不会做你的代码测试题。这些题目也会增加面试的时间,从而延长整个雇佣过程。但这一切都不能增加候选人的数量。

更重要的是,代码面试并不能很好地模拟真实工作。

Google的研究发现,优秀的团队都拥有一项特质,叫做“心理安全”(https://rework.withgoogle.com/blog/five-keys-to-a-successful-google-team/)。只有当团队的所有人都愿意承担风险、愿意身处弱势时,团队才能达到最佳状态。

这跟代码面试完全不一样。候选人通常会感到焦躁、感到压力,担心一个小错误就会丢失这份工作。因此你没办法获得候选人的最佳状态。

更糟糕的是,这些题目会刷掉那些没有太多自由时间的候选人。通过这些题目只会让你筛选出那些有空闲时间的人。因此你的候选人会更年轻、更没有经验。你还会错过一些其他人,如未婚父母或需要照顾家中病人的人。

 

有更好的办法吗?

 

虽说忠言逆耳,但是你必须去和你的候选人谈话。你需要去了解他们,需要和他们对话。也许这很难,但从整体来看这种方法更容易。

作为面试官你必须提高技术力。

 

面试技巧:前提条件

 

代码面试是空中楼阁,看起来很美好,唯一的缺点是无法筛选出好的候选人。你需要思考什么样的技术力和品质对你的团队最有价值,而代码面试只不过是你偷懒的借口而已。

招聘很难,想做好招聘可能需要掌握一系列的技巧。站长站,但是,有些技巧可以立即提升你的面试水平:

  • 事先规定你需要的候选人的特征,该规定需要做到具体、详细;

  • 询问候选人一系列固定的问题;

  • 在面试之后、征求他人意见之前,记下所有面试的反馈;

  • 练习,练习,再练习。

 

不需要代码的方法

 

不需要写代码就能衡量候选人的方法可能有一万种。我常用的三个主要方法可以覆盖许多不同的技能。在面试过程中,我们会谈论候选人的经验,要求他们做一些代码审查,并与别人合作设计一个系统。

下面我会详细解释这个过程。

我试图通过这些方法找到真正能够胜任技术工作的候选人,并且他们必须能在单纯的编程技能之外给团队带来价值。通常在一次面试中我能在大约一个小时内覆盖所有三个部分。我有信心这些信息能让我找到好的候选人。

深入挖掘他们的经验

许多团队已经这样做了。他们会在面试一开始花几分钟,询问候选人之前的工作,他们对工作的态度,等等。大多时候这就像随意谈话一样。

但这是不对的。

记住这是面试。你需要尽可能地理解他们构建系统时使用的技术。

为了做好这一点,你需要在面试开始之前仔细阅读他们的简历。这不是开玩笑,在面试开始之前至少花上10分钟仔细阅读(不是略读)简历,如果花30分钟时间则最好。要从简历中尽可能多了解些他们之前的项目,Google一下看看能否找到他们项目的公开信息。面试时挖掘背景信息所花的时间越少,就越能获得好的效果。

在面试中,要求候选人谈谈他最近最感兴趣的项目。要练习主动的倾听,要学会参与。假装你是他团队中的一员,或者假装你们是在做架构审查。你要努力了解他们构建的东西以及构建的方法。这样做的好处和坏处是什么?要让候选人知道,不知道答案无所谓,但重要的是能勾起你的好奇心。

下面是我认为能获得好的答案的问题:

  • 你在项目中的职责是什么?这个问题本身并不是决定性的。即使在项目中承担的职责很小,他们也可能很适合你们的团队。你的候选人也许正是因为没能获得重要的职责而在寻找新的机会。因此,知道他们过去的职责会很有帮助。

  • 你从他人那里获得了什么帮助?无法感受他人的帮助是个极其危险的信号。即使是个人项目,也一定需要别人的帮忙。你肯定不想要一个以自我为中心的同事。

  • 给我介绍下那个功能的工作原理。解释下数据的来源和去向、存储方式以及这一切能带给最终用户的好处。这个问题的答案足以吸引你的好奇心。

  • 这个项目中最糟糕的技术债务是什么?好的工程师必须理解他们做出决定时需要付出的代价。问完这个问题,可以继续询问他们怎样改正这些问题,或者尚未改正的理由。

  • 有没有出过生产环境下的bug或服务中断?测试下他们是否理解bug的原因,电视剧大全,以及团队解决bug的方法。他们是否提前预期到了bug?下次怎样才能避免同样的问题发生?

这一部分面试能让你直接了解候选人的经验。做好这一部分还能让你了解他们如何感谢别人或责备别人。你将会了解到他们如何在两难的工程问题上做出抉择,他们会与你分享最近的教训,他们与别人沟通技术的能力应该也很明显。

如果他们选择了不太适合的项目,可以考虑谈论其他项目。所谓不太适合的意思是项目不够复杂或他们记不清的情况。

注意,这一步要避免询问类似于“告诉我你解决过的最难的bug”之类的问题。要求别人回忆系统的某一部分的具体原理会带来大量的虚假负面判断。人们不可能拥有他们修复的bug相关的一切知识,这种问题会给面试过程带来很大压力。

让他们审查你们的代码

这项活动一半是代码审查一半是角色扮演。你可以借此筛选出那些能够提升团队整体代码质量并促进办公室氛围的人。

下面是代码审查过程中需要关注的一些方面:

  • 他们怎样与代码的“作者”交流?交流是否有用?是否高效?是否友善?

  • 他们会着重哪些问题?是否能明确表达出他们的疑问?他们是否会立即指出哪些无关紧要的问题?

  • 他们是否善于阅读自己不熟悉的代码?

这个方法需要提前准备很多东西。你需要找到或编写一段代码供候选人审查。你还需要为你希望候选人找出的问题创建一个优先级列表。不要让面试管当场出题,一定要事先准备好。

在选择需要审查的代码时,不要选择产品代码。你的候选人没有你所拥有的背景知识,这样做实际上是将候选人与你的同事比较,而不是与其他候选人比较。

努力降低代码示例中的复杂度。面试的时候,候选人没有太多时间阅读代码,而且很可能他们并没有想到会做代码审查。热身就要花很长时间。

在代码中加入一两个真实的bug,但不要强调找bug。一般来说,代码审查并不是个好的找bug方法,特别是审查者从来没有见过代码的情况下。能自证的bug(如给需要数组的函数传递字符串)最好。在你的优先级列表中,bug的优先级应该是最低的,bug应该是给极其优秀的人的加分项。

最后,代码应该做一些实际的事情。如果你的公司很出名,那可以选择你的产品简化版本。但如果你需要花大量时间为候选人提供背景信息的话还是算了。

最好的选择要么是虚构的代码(也许可以选择本文竭力避免的代码面试中用到的代码),要么是开源代码中的一个拉取请求。

一旦决定了要审查的代码,你应该期待候选人找出下面这些东西:

  • 过于糟糕的拉取请求的描述或提交信息;

  • 能用但无法自洽的代码;

  • 过于复杂的代码(需要重构的代码);

  • 混乱的变量或方法名;

  • 过度设计的代码(即实际上永远不会用到的功能)。

如果代码中没有足够的问题,就多加一些。

这里有个潜在的问题,我还没有确定的答案。这个问题是:你是否应该提前将代码发给候选人?

如果你这样做,就又给那些有空闲时间的人以巨大的优势。如果不这样做,就要面临增加面试压力的风险。

我倾向于后者。好的面试官可以减轻压力,方法之一就是让面试者提前知道他们将做代码审查,你也可以在审查开始之前介绍你的期望。

共同设计系统

作为面试官,你最重要的任务之一就是判断候选人是否能完成要求他们完成的技术工作。好的评价方法应当尽可能避免虚假的正面和负面判断,同时在更广泛的技术水平范围内区分候选人。

即使是新手也应当能针对问题取得一些进展。最高级的候选人应当能快速找出他们无法立即解决的问题。

这种方法我从大学时代就开始使用,后来在业界用了二十多年。这种方法非常有效。

这种方法是什么?

协同设计系统的意思是与你的候选人共同设计一个工具、平台或项目。不需要写代码或伪代码,只需要讨论系统的设计思路和做出的取舍,还要提出这些取舍可能带来的问题,以及解决问题的方案。

这种方法之所以有效,是因为新手工程师和高级工程师之间的主要区别就是他们能预见到的问题的数量。凭借经验可以造就更强壮的系统设计,也能随时解决新问题。

怎样使用这种方法?

首先你的团队需要选择一个希望候选人“构建”的项目(所有候选人应当使用同一个项目。长时间这样做,面试官就能做出更好的评价),自己做一次练习并计时。面试时要让候选人知道系统设计大概要花多少时间,并告诉他们不可能完成所有设计。他们应当提前了解预期的产出。

花上几分钟解释基本的需求。如果需求无法用几句话解释清楚,那可能不是个好项目。例如,你的项目可以是构建一个与某个著名的社交媒体平台相似的东西,比如你无需解释Instragram的工作原理。

事先提供一切你认为价值不大的东西。然后询问候选人他们希望首先构建的部分。然后继续讨论新功能,直到时间用完。

如果候选人很容易就完成了这一切,那么可以提高复杂度。如果他们表现得很困难,就降低复杂度。

项目的难度可变,这样就能深入了解候选人的技能水平。就像是对候选人水平做二分查找一样!

选一个项目

这项活动的关键就是需求必须易于理解。如果你公司的产品很出名,可以利用它做为起点。否则,选一个知名的网站(如Facebook)。项目应当与候选人入职后要做的工作相关。拿我们来说,我们有两个项目,一个用于后端招聘,一个用于前端招聘。

后端项目的主要关注点是流行社交网络的底层系统。前端项目会提供一些简化了的产品功能截图,并询问候选人如何构建(组件怎么定义、组件间交互用什么方法等)。

示例:构建Facebook

首先,我们会介绍任务。告诉候选人我们要构建一个类似于Facebook的网站。我们假设现在这个网站包含了用户、认证和一些其他功能。

此时,我会询问候选人怎样才能构建最小功能的Facebook。我们喜欢这个问题,因为这个问题能看出候选人怎样考虑产品上的需求,也可以给之后的决策和取舍的讨论提供基础。

此时,我会使用白板记录下他们的想法。这样能使我参与其中,保证我之后能理解他们的设计。如果我理解错了,他们会立即注意到并纠正。

候选人可能会告诉我,最小功能集合包含好友、状态更新、新闻源,以及点赞的功能。问问他们挑选这个功能列表时的原则。是否漏掉了什么明显的功能?是否包含了不必要的功能?他们的思考过程比功能列表本身更重要。然后,问问他们打算先做哪个。假设候选人决定先做“好友”功能。

候选人会有不同的想法。一些候选人可能会提出不可行工作的方案,但不应该剥夺他们的机会。最优秀的候选人应该能很快就完成这个阶段。

我们假设候选人告诉我,他要建一个表来保存好友关系。这个表应该包含好友关系的发起人和接收者。

然后继续挖掘。在Facebook中的好友关系是双向的。怎样才能在数据库中表示?这种表示方法对系统设计有什么影响?

选择之一就是不需要做任何特别处理。查找给定用户的好友时用两列同时查找。另一个选择是在好友数据库中保存两份数据,每个数据表示一个方向。如果这样做,那么删除好友时要同时删掉两条数据。讨论两者的取舍。

下个话题可能是如何处理好友请求。他们可能会选择在“好友”一栏添加一个“接受”按钮。他们可能会建立新的表保存好友请求。接下来可以讨论黑名单和垃圾请求等话题。

此时好友的话题基本上说完了,可以继续讨论下一个功能。随着新的功能不断加入系统,讨论各个功能之间的交互是件很有意思的事情。

假如候选人无话可说也没关系!你可以提出一种解决方案,问问他们的想法。这种方案的优缺点是什么?要是他们还是不理解,可以试着讨论其他的功能。

这项活动中我最喜欢的地方就是它很有意思。如果面试官表现很好,候选人也积极参与,那么最终整个面试过程可能不怎么像面试,而更像是一次与同事间就新项目进行的谈话。

而这正是候选人即将担任的角色。完美。

 

什么时候应该用代码面试?

 

尽管我很不喜欢代码面试,但有时候也有用:

  • 确定入门级程序员是否能够编程;

  • 如果你的公司强制进行结对编程,那么在面试中进行结对编程可以当做是以后工作的预演;

  • 一个角色需要许多特定的编程技能,而你没有太多时间去教他们,当你在两个高级职位名称之间犹豫不定时尤为如此;

  • 从代码面试到无代码面试的转变过程中不要突然转变,给自己一段转变的时间,可以帮你建立无代码面试的技能。

最后,如果团队的面试技能欠缺,就需要利用代码面试。代码面试的效果不太好,而且也有许多缺点。但是,它非常容易实施。即使是没有经验的面试官也可以很好地处理代码面试。

如果你正是这样的人,那么培养自己的面试能力应该是最优先的——雇佣错误的人是最昂贵的错误。

 

结论

 

只要一点点练习,你的团队就能在这种无代码面试中做得很好。他们能在较短的时间内做出更好的雇佣决策,而且面试也能招来更多的候选人。

我希望这篇文章对你有帮助。如果有问题,请在评论区留言。希望你能在下一次面试中干掉代码面试!

 

posted @ 2018-10-05 16:19  万象更新新  阅读(201)  评论(0编辑  收藏  举报