电话面试若做得不好,后果会很严重——所有参与其中的人都会浪费大量的时间。

关于电话面试,Steve Yegge的那篇“Five Essential Phone-Screen Questions”(电话面试时要问的5个基本问题)最具代表性,也是目前你能找到的最好的文章——这是Steve在亚马逊工作期间送给我们的礼物。

Steve开篇就指出面试官应该尽最大努力去避免的两个错误:

  1. 不要让候选人主导面试过程。大部分时间都应该是面试官在说话。面试官要引导整个对话过程,直到自己满意为止(要么确认候选人知道答案,要么候选人放弃了)。
  2. 小心只会一招的“小马驹”。只会一种特定的语言或编程环境,并且对其他东西一窍不通的候选人,小心啦,这是一个巨大的红色警告信号。

电话面试的目的,不是让候选人复述他们做过的事情。面试官应该把他们从舒适区推出去一点,问他们一些相关的问题,但那些又是他们以前没见过或没做过的。理想情况下,你要了解这个人在面对新事物(比如你的代码库)的时候会做出什么样的反应。

为了让电话面试进行得更加顺畅一点,我在下面罗列了你在面试软件开发工程师时需要问的5个基本问题。它们不能保证你会找到最棒的候选人,但能阻止相当一部分的人蒙混过关。

1)编程。候选人需要用C、C++或Java写一段简单的代码,要求语法正确。

2)面向对象(Object Oriented,简称OO)的设计。候选人需要说清楚OO的基本概念,并且想出一些类来为一个简单的问题建模。

3)脚本编程和正则表达式。候选人需要描述一下,如何在50000个HTML网页里把电话号码都找出来。

4)数据结构。候选人需要证明他对最常用的数据结构都有着基本的理解。

5)位与字节。候选人需要回答几个关于位、字节和二进制数字的简单问题。

请注意:我们这里想要发掘的,是在前面所说的某一方面完全无知的人。如果他们挣扎了一下,然后还是回答出来了,也就算过了。他们甚至可以要求一点小小的线索或提示。我不介意他们反应迟钝或动作缓慢。我们要找出的,是那些对问题中所涉及的领域极端困惑、毫无头绪的候选人。

当然,你可能需要对这个过程进行一些裁减,以适应你的具体情况。也因此,我建议你到网上去完整阅读Steve的这篇文章。Steve也确实提供了一些例子,以使我们能够更快地步入正轨:

(面向过程的)编程

  • 写一个函数把一个字符串反转过来。
  • 写一个函数计算第N个斐波那契数。
  • 打印小学乘法口诀表,直到12×12为止。
  • 写一个函数把一个文本文件里的所有整数加起来(文件里每个整数占一行)。
  • 写一个函数把1~99的所有奇数都打印出来。
  • 在一个整型数组中找出一个最大的整数值。
  • 把一个RGB值(3个单字节的数字)格式化成6位数字的16进制字符串。

优秀的候选人是很容易在编程问题上脱颖而出的。他们只需使用基本的循环或递归,也许再加上稍许格式化的输出或文件I/O操作。我们想要知道的是,候选人是否真的知道怎么去写程序。尽管Steve的文章发表得比较早,本着对读者负责的态度,我在这里还是要提一下"为什么程序员不会编程"这篇文章(本章第一节)。与“Fizz-Buzz”问题的作用是很相似的,被面试的人常常做不出来也是令人震惊的事实。这有点不可思议,就像一位有潜力的卡车司机不知何故找不到油门踏板或换档器……

面向对象的编程

  • 设计一组卡片,使它们可以用于不同的卡片游戏程序。
  • 用一系列类为动物王国建模,并用于一个"虚拟动物园"程序。
  • 设计一些类来表现文件系统。
  • 设计一个OO表示法来为HTML建模。

我们这里姑且不论OO设计的优点或缺点,我们也不要求一个全面的、底层的OO设计。这些问题,只是为了揭示候选人是否熟悉面向对象的基本原则;更为重要的是,他们能否创作出面向对象的解决方案。正如“The Monopoly Interview”一文所述,我们期望看到的是他们对基本原则的理解。

脚本编程和正则表达式

Steve的团队去年接到一个任务,要把藏在50000个亚马逊网页模板里的电话号码都删除,因为那些号码很多都已经废弃不用了。他们还想把给客户的联系信息都集中到一个页面上。

假设你在这个团队里,你必须先找出包含美国电话号码的所有网页。我们把问题简化一些,假设50000个HTML文件都存放在一个名叫“/website”的Unix目录下。我们有两天的时间找出所有的文件(只需列出文件名和路径),然后通知编辑团队。HTML文件里的电话号码格式可能是(xxx)xxx-xxxx或xxx-xxx-xxxx。

你会怎样来解决这个问题呢?记住,我们的时间有限,只有两天哦!

这个问题其实很有意思。据Steve说,来应聘软件开发工程师的所有候选人中,有25%~35%的人根本不知道从何入手,即便给了他们很多暗示甚至完全不限制面试时间也于事无补。其实,我们期望看到的是,候选人表现出一丝不愿意"重复发明轮子"的勉强之情,然后尝试使用脚本语言和正则表达式来解决问题。在我看来,通过这个问题还能看出,开发人员在动手编写自己的程序之前,他会不会脑子灵活一点先去网上搜一下,或者找一下是否有现成的代码可以重用,也许完全可以避免好几天时间的赶工。

数据结构

  • java.util里有哪些数据结构最为常用?
  • 你在什么情况下会使用链表(linked list),而不用向量(vector)?
  • 你能用树(tree)来实现一个映射(map)吗?用列表(list)来实现呢?
  • 你能按级打印出一棵树的各个节点吗(先打第一级,再打第二级,然后第三级,依此类推)?
  • 哈希表(hash-table)的插入操作在最坏的情况下性能怎么样?二叉树(binary tree)又会怎样呢?
  • 实现一个优先队列(priority queue)有哪些方法?

候选人应该有能力证明,他们对最常用的数据结构有着基本的理解。说白了,也就是数组(array)、向量(vector)、链表(linked list)、哈希表(hash-table)、树(tree)和图(graph)。他们还应该知道算法复杂度"大O"的基本原理:常数阶、对数阶、线性阶、多项式阶、指数阶和阶乘阶。如果他们说不清楚,那就是个巨大的警告信号。

位与字节

  • 告诉我怎么测试一个字节的最高位是否为1。
  • 写一个函数,计算一个给定的整数值有多少个二进制位;也就是实现这样的函数:int countBits(int x)。
  • 写一个函数,对于一个给定的整数,如果它的二进制模式从正向看和反向看是一样的,那就返回true;也就是实现这样的函数:boolean isPalindrome(int x)。

拿Steve的话来说,“电脑没有10个指头;它们只有一个。人们必须明白这一点。”如果你问一个候选人,“2的16次方是多少?”他不应该无言以对,因为这是一个特别的数字,他们没理由不知道。他们同样还要知道AND(与)、OR(或)、NOT(反)和XOR(异或)的基本原理,以及操作二进制数的AND跟逻辑上的AND之间的区别。你甚至还要问他们有符号数和无符号数之间的差别,以及为什么说位移操作很重要。他们应该能解释那个经典的玩笑话:“为什么程序员认为10月31日跟12月25日是同一天?”

做一次周详而彻底的电话面试很费工夫。但那是值得的!通过电话面试每淘汰一个候选人,至少为后面需要参与现场面试的人节省8小时的时间。每当有不合格的候选人进入现场面试这个阶段,你都应该自问一下:“将来我们怎样才能把这种候选人在电话面试阶段淘汰掉呢?”