译者:杰微刊兼职翻译张万程
这篇博客最初是我们发给候选人的准备资料,现在我们决定将其公开。
在编程面试中,好的程序员不一定能通过,从某种意义上来说,代码写得好在面试中起的作用是出乎意料地有限。要成为一个颇有建树的程序员,你必须能够解决一些比较大的纷繁复杂的难题,这通常要数星期甚至数月。面试的时候,每个问题都不会超过一个小时。要想面试过程中表现出众,你需要能快速地解决小问题,并且把思路和想法清楚地表述出来。看出来了吧!后者是一个不同的技能点。话说回来,面试官们一般都没经过专门的培训,也不怎么上心(人家宁愿去写代码),问的问题也跟实际工作差得很远。他们会带来偏见,模式化,缺乏标准。
创办Triplebyte后,这点我非常清楚。我们面试工程师的时候,不看简历,而是快速把他们送到YC companies工作场所。在过去的9个月中,我们面试了超过1000个程序员。我们的关注点在于候选人的实际编程技术,让候选人从几种方法中选择一种来进行评估。这意味着,跟我们工作的很多程序员(非常有才的),他们没有正式的CS培训。其中很多人,在通常所见的面试中,会表现很糟糕。他们解决棘手问题如同家常便饭,却被45分钟的算法问题难倒。
好消息是,面试是门技术,是可以被掌握的。通过培训我们成功地让很多候选人在面试上有更好表现。确实如此,Triplebyte候选人在YC公司面试时,通过面试的最直接因素不是天份,而是勤奋。
我并不认为一个好的程序员需要特殊的面试技巧才能做好面试。但是现状就是如此。我们在Triplebyte工作,就是要改变这种情况。如果你对我们做的事情感兴趣,请看一下我们操作。同时,如果你想在面试中表现更佳,这篇博客就描述了我们认为你怎么才能有效的做到这一点。
1. 热情
热情在面试中的作至关重要。在没有通过面试的Triplebyte候选人中,有一半是由于非技术原因。公司称之为 “文化不符”。但是,文化不符,十之八九,意味着缺乏对公司所做事情的热情。公司需要的,是对工作感到兴奋的人。对公司来说,这一点和技术一样重要。道理很明白。兴奋的候选人工作起来会更开心,也会更努力。
问题在于热情是可以被假装的。有些人跟他们聊过的每一个公司,都说这是梦想职位,他们有办法说服公司,但是有些人就不能(即使他们对工作真的感到很兴奋)。这种情况我们见的太多了。解决方法是要学习如何更好地来展现热情。我不是说你可以说谎。但面试跟约会一样。在第一次约会的时候,没有一个人愿意被告知自己是众多选择中的一个,即使这通常就是事实。类似的,很多程序员只是想得到一份好工作,拿到一份好报酬,仅此而已。但是面试中,这么说就错了。最好的方法,就是在面试之前做些准备,记录下你觉得这个公司令人兴奋的地方,当面试官问你是否还有问题时,把这个笔记拿出来。读一读公司最近的博客和新闻稿,找些让你感到兴奋的地方,记录下来,这些都是点子的来源。
这个主意看起来简单。我可以想象,你也许一边读一边点头称是。但是,很少候选人可以做到(所有面试官都可以告诉你这一点)。认真准备记录,列出为什么这个公司让你感到兴奋,这样做真的可以提高通过率。你甚至可以在面试中翻一翻笔记。带过来的笔记表明了你真的做了准备。
2. 学习常见的面试点
面试题中,很大一部分是关于数据结构和算法。不管是好是坏,事实就是如此。我们从有YC公司面试经历的的候选人中收集问题习题(之后在另外一篇文章里面,我们会做一个深入的分析),算法问题占了70%以上。你不需要成为一个专家,但是知道下面的算法和数据结构,会有很大帮助:
①. 哈希表 (Hash tables)
②. 链表 (Linked lists)
③广度优先搜索,深度优先搜索 (Breadth-first search, depth-first search)
④快速排序,归并排序(Quicksort, merge sort)
⑤二分查找(Binary search)
⑥二维数组(2D arrays)
⑦动态数组(Dynamic arrays)
⑧二叉搜索树(Binary search trees)
⑨动态编程(Dynamic programming)
⑩ BIG- O分析(Big-O analysis)
编程背景不同,这张单子,也许看来很微不足道,也许很让人恐惧。关键就在这里。在实际网络编程中,这些概念很少出现,在面试中,却很常见。如果你是自学的,或者早已毕业多年,这些概念对你来首有些陌生,重新学习一下,在面试中能做的更好。即使你早已知道这些,重复温习也会有帮助的。很大一部分的面试问题就是广度优先算法或者用哈希表来计算特异值。你需要能能够写一个BFS代码,能够理解哈希表是如何实现的。
学习这些东西并不像我们想像中那样难。算法经常用学术性的语言来描述,这让人心烦。但是其本质,上面表中所列出的没有一个比当前web app架构更难懂。如果你可以建一个web app,那你也可以学会这些。
我推荐的资源,是一本由Steven Skiena写的书,叫做《算法设计手册》 (The Algorithm Design Manual )。书上第三章到第五章,涵盖了上述材料,讲的很到位,讲述方式也非常直接。虽然用到了C语言和一些数学符号,不过解释得很清楚。 Coursera上面也有些很棒的算法课,比如,斯坦福大学的算法课(Algorithms: Design and Analysis),重点介绍了面试中常见的考点。
学习算法和数据结构大有裨益,因为它不仅是面试要遇到的东西,而且在算法课上解决问题的好方法在通过面试时同样凑效。学习算法会让你的思维模式进入到面试状态。
3. 从面试官那里获得帮助
面试官会帮助候选人的。他们会给暗示,给反馈,通常也会引导整个面试过程。但是他们不会同等程度地帮助所有候选人。有些程序员可以得到很大的帮助,面试官不会故意保留信息而不帮助他们。有一些程序员,得到一些提示,就可能被苛刻地指责。你肯定希望得到帮助。
这就要谈到面试过程和交流的问题。如果面试官喜欢这个过程,你跟他们之间的交流也很不错,他们不介意提供帮助。通过遵守一些步骤,这样的情况变得更有可能。我推荐的步骤是:
①. 问问题(Ask questions)
②. 详细讨论一个暴力破解方案(Talk through a brute-force solution)
③. 详细讨论一个优化方案(Talk through an optimized solution)
④. 写代码(Write code)
被问到问题后,首先要理清问题到底是什么。这是“学究”时间。对能想到的任何模糊之处,都要问个明白。问一问边界情况。你可以想出一些特别的例子,给定输入值,确保你的期望值是准确无误的。即使你对答案很有把握,也要问。提问是个机会,可以让你想到边界情况,并充分审视问题(如何处理边界情况也是面试官看重的一个方面),提问也给你一些时间,让你在开始解决问题之前,集中思路。
接下来,针对你能想到的问题,要详细谈一谈那种最简单的暴力解决方案。你要说出来,而不是直接去写代码,因为谈话时思路更快,对面试官来讲,谈话也能更有吸引力。如果能和面试官一起交流,他们也会参与其中,并提供建议。如果你直接退到写代码上,你会错过这次机会。
候选人经常忽略掉暴力破解方法,他们觉得暴力方案太显而易见了,或者太不对了。这是误区。你要保证的是,对每一个被问到的问题,给一个解决方案(即使它的耗时是指数级的,或者需要一个 NSA 超级电脑)。当你在描述暴力解决方案的时候,要询问面试官是否想让你去实现它,或者继续想出更有效的方案。正常情况下,他们会让你提出一个更有效的解决方案。
一个有效方案的提出过程,跟暴力方案一样。还是要说出来,不要直接去写代码,尝试着跟面试官交换看法。如果顺利的话,被问到的问题可能跟你以前所见过的类似,这样答案就很明了了。如果情况并非如此,想想你所熟悉的问题里面,哪些与其类似,提出来让面试官知晓。很多面试问题,其实都是经典CS算法的应用,只是略微模糊些而已。面试官通常会引导到这个算法的,但是,你要先开始。
最后,你有了个好方案,并且你和你的面试官都认同这一点,你就可以开始写代码了。代码要敲在计算机里,还是写在白板上,取决于公司的具体情况。因为方案已经有了,写代码就很简单。想要加分的话,可以问问你的面试官,是否需要写测试用例。
4. 谈谈技术选择
编程面试主要是由编程问题组成,这也是本文目前一直所讨论的。但是,你也许会遇到系统设计问题。不少公司好像很热衷于此,尤其是对一些有经验的候选人。在系统设计问题中,候选人被问到如何去设计一个复杂的真实系统。比如Goolge地图,社交网络,或者银行API。
你可以发现,回答这些问题需要专门的知识。显然,没有人想让你去设计Googl地图 (那会花费很多人很长一段时间)。但是他们确实希望你能对这些方面有所了解。好消息是这些问题通常涉及的是web后端,你可以通过阅读资料,来获取信息。关于需要了解的地方,下面列出了一个不完全的清单:
① HTTP (协议层面)
② 数据库 (索引,查询规划)
③ CDNs
④ 缓存 (LRU cache, memcached, redis)
⑤ 负载均衡 (Load balancers)
⑥ 分布式工作系统 (Distributed worker systems)
你需要理解这些概念。更重要的是,你要理解他们是如何组合在一起,来构建出真实系统的。最好的方法是阅读,看看其他工程师是如何使用这些概念的。这篇博客(http://highscalability.com/)是很好的资源。它对真实公司的后端架构有着详尽的评论。对于清单上的每个概念,你都可以了解到,他们是如何应用在真实场景下的。
一旦你完成了阅读,回答系统架构问题就是个过程问题。先从最高层开始,然后往下移。在每一个层上,询问你的面试官具体的规范(你是建议一个简单的开始呢?还是要听听成熟系统如何运作呢?),要谈到一些不同的配置(把读到的内容做些应用)。讨论权衡是关键点。
比起你的设计本身是否优秀,你的面试官更在意的是,你能否可以讲出设计的优势和劣势(权衡)。这一点要多多练习。
5. 突出结果
第三类你可能遇到的问题是关于项目经验。面试官会让你介绍曾经做过的项目。在这个问题上,很多程序员可能犯错误,他们介绍的是技术层面有趣的小项目。一些程序员可能选择介绍如何实现神经网络的分类器,或者如何写出Twitter语法机器。这些都是错误的选择,因为面试官很难判断项目的应用范围。
很多候选人夸大了这些简单的小项目(很多情况它们从未真正工作过),面试官无法判断你是否真正做过。
解决方法是,选择一个有结果的项目,并且突出这些结果。这意味着选择那些技术上不太有意思,但是值得一讲的项目。思考一下你所参与的带来最大社会影响的项目。如果你写过一个iOS游戏,有5万人下载了,下载量就是个好的选择。如果你在实习中写了一个admin管理员界面,并部署在所有的管理员电脑上,这个部署也是个好的选择。
选择介绍一个实际的项目,也是向公司展示,你的注意力是放在实际的工作上。程序员过度关注有意思的技术,是一个反面典型,公司都会屏蔽掉(这些程序员有时候并不多产)。
6. 使用一种动态语言,但要提到C
我推荐你用一门动态语言,比如Python, Ruby或者JavaScript。当然,你应该用你最熟悉的语言。但是我们发现很多人想用C,C++或者Java, 他们认为这些才是真正的编程语言。
有些经典的面试书会推荐使用Java或者C++。但是我们发现,在创业公司,这是个糟糕的选择。用动态语言,面试者能做得更好。这是事实,因为动态语言有更紧凑的语法,灵活的类型,列表和hash。这些语言非常自由。当写复杂程序的时候,这些语言也许有缺陷(也是个争议点),但是在白板上写二分法搜索还是很棒的。
不管你用哪种语言,提到工作中使用过其他的语言都很有帮助。公司想屏蔽掉的反面典型是只会一种语言的人。如果你真的只会一种语言,你不得不全部依靠它。但是如果你在工作中或小项目里用过多种语言,一定要告诉面试官。如果你还使用过低级语言,比如C,C++,Go 或者Rust, 提到这一点也非常有用。
Java, C# 和PHP是有问题的例子。在上一个博客中,我们提到过,创业公司对这些语言存在偏见。有数据显示,使用这些语言的程序员,面试通过率更低。这不公平,但是这是事实。如果你有其他的选择,我建议你在创业公司面试时不要使用这些语言。
7. 练习,练习,练习(重要的事情说三遍)
通过练习面试问题,你可以在面试中表现更好。这是真实的,因为面试是有压力的,而压力会损害表现。解决之道就是多练习。通过多接触,面试变得越来越没有压力。随着经验的增加,这会自然而然发生。即使在单次找工作中,我们也发现,候选人往往不会通过最初的面试,然后随着信心的积累,就能通过越来越多的面试。如果压力是你需要克服的,我建议你从练习承压开始。收集一个面试问题大全,然后解决它们。
为每一个问题设置20分钟的计时器,跟时间赛跑,快速回答。练习将答案写在白板上(不是所有公司都会这么要求,白板是最坏的情况,你要这么练习)。纸笔是白板的替代。如果你有朋友可以帮忙,轮流面试对方是最好的。大量的阅读面试问题,可以在真实面试的时候为你提供思路。很大一部分的问题是重复使用的(不管是全部还是部分相同)。
即使最有经验的候选人也会得益于此。面试是一个跟程序员实际工作完全不同的技能点,是可能退化的。但是有经验的程序员总是觉得自己不需要为面试做准备。他们学习的更少。这就是为什么初级程序员通常比有经验的程序员面试方面更出色。公司也知道这一点,所以讽刺的是,有些公司告诉我们,在面试方面,他们对有经验的程序员制定的标准更低。
8. 提资历
面试官有资历偏见。Triplebyte的候选人如果有大公司或者名校的经历,通过面试的机率要比普通候选人高30%(根据我们的资历盲选测试结果)。我不喜欢这样。这不是任人唯贤,而是一种糟糕的做法,但如果你有这些资历,你要设法让你的面试官知道。你不要天真的认为他们看完了你的简历。
9. 罗列offer
如果你曾经读过给创始人的募款建议,你就会知道让第一个VC给出投资offer是最困难的。一旦你有了个offer,其他的就会涌入。对工作offer来讲,也是一样的。如果你已经拿到一个offer,一定要在面试中提到这一点。提到其他的offer会更让面试官更倾向于录取你。
这就不得不提到一种策略,把你所有感兴趣的公司都列出来,按照相反的顺序来进行面试。在之前的面试中表现出色可以增加你拿到最心仪公司offer的几率。你应该这么做。
总结
在面试中脱颖而出是一种技巧。可以帮助你成为一个伟大的程序员,但这种帮助也是很有限的。每个人都有一些失败面试经历,合理的准备可以帮助提高面试通过机率。激情很重要,对面试的经历也会有所帮助。很多候选人是没有通过面试的原因是缺乏激情而不是缺乏技术。在面试过程中面试官也可以帮助候选人,如果你遵循一个好的流程并且表达清晰,他们会帮助你。实践总是有帮助的。
这不是理想的状况,面试所需要的准备工作驱使程序员去学习一些加分的技能,而不是创建伟大的软件,这浪费了所有人的时间。公司应该改进他们的面试流程,减少对计算机学历背景的偏见,避免死记硬背,并且要排练面试流程。这也是我们在Triplebyte所做的工作。我们的目的是帮助程序员找到工作,而不是看简历。我们让程序员自己挑选一些领域来做人才评估,并且不断地改进面试流程。我们乐于在有限情况下帮助你在初创公司找到一份工作。你可以从这里开始。但是现状如此,在做出改变之前,程序员应该知道如何做准备。