如何通过编程面试
这篇文章最初是我们发给考生的准备材料,但我们决定公开发布。
成为一名优秀的程序员在编程面试中的作用出奇地小。要成为一名高效的程序员,你需要能够在数周甚至数月的时间里解决庞大而复杂的问题。相比之下,面试中每个问题的持续时间不到一小时。因此,要想在面试中表现出色,你需要能够在压力下快速解决小问题,同时清晰地解释你的想法。这是一项不同的技能[1]。除此之外,面试官通常训练不足、注意力不集中(他们宁愿编程),并且会提出与实际工作脱节的问题。他们会带来偏见、模式匹配和缺乏标准化。
在运营 Triplebyte 的过程中,我清楚地看到了这一点。我们面试工程师时不看简历,并快速将他们送入顶尖科技公司的现场面试。在过去的九个月里,我们已经面试了超过 1000 名程序员。我们非常注重实践编程,并让候选人从几种评估方式中选择一种。这意味着我们与许多(非常有才华的)程序员合作,他们并没有接受过正规的计算机科学培训。这些人中的许多人在面试中表现不佳。他们早餐就能吃掉那些庞大而繁琐的题目,却对 45 分钟的算法挑战望而却步。
好消息是,面试是一项可以学习的技能。我们已经成功地指导求职者在面试中表现得更好。事实上,Triplebyte 求职者能否通过公司面试,最关键的品质并非天赋,而是勤奋。
我从根本上不认为优秀的程序员应该学习特殊的面试技巧才能在面试中表现出色。但现状就是如此。Triplebyte 正在努力改变这种现状。如果您对我们的工作感兴趣,欢迎您查看我们的流程。同时,如果您确实想提高面试技巧,这篇博文将介绍我们认为最有效的方法。
1. 保持热情
热情对面试结果影响巨大。大约50%的Triplebyte候选人在公司面试失败是因为非技术原因。公司通常将此描述为“文化契合度低”。然而,十有八九,文化契合度仅仅意味着对公司业务充满热情。公司希望候选人对公司的使命充满热情。在许多公司,热情与技术技能同等重要。这是有道理的。充满热情的员工会更快乐,工作也会更努力。
问题在于,这种热情是可以伪造的。有些求职者设法让每家面试的公司都相信这是他们梦寐以求的工作,而另一些求职者(他们真的对这份工作充满热情)却无法说服任何人。这种情况我们屡见不鲜。解决办法是让每个人都更好地展现自己的热情。这并不是允许撒谎。但面试就像约会。没有人希望在第一次约会时就被告知自己只是众多选择中的一个,尽管通常情况下确实如此。同样,大多数程序员只是想要一份薪水不错的好工作。但在面试中这样说是错误的。最好的方法是在面试前准备好笔记,记录你对这家公司感到兴奋的地方,并在面试官询问你是否有任何问题时提出来。一个很好的想法来源是阅读该公司最近的博客文章和新闻稿,并记下你觉得令人兴奋的内容。
这个想法听起来很简单。我猜你读到这里肯定点头表示同意。但是(任何参加过面试的人都会告诉你)只有极少数的求职者会这样做。认真准备笔记,说明你为什么觉得这家公司令人兴奋,确实会提高你的通过率。你甚至可以在面试时参考这些笔记。带上准备好的笔记表明你做好了准备。
2. 学习常见的面试概念
面试题中很大一部分都涉及数据结构和算法。无论好坏,这都是事实。我们从公司面试的候选人那里收集了问题详情(我们将在以后的文章中对这些数据进行深入分析),其中算法题占面试题总数的 70% 以上。你不需要成为专家,但了解以下算法和数据结构列表对大多数公司来说都会有所帮助。
- 哈希表
- 链接列表
- 广度优先搜索、深度优先搜索
- 快速排序、合并排序
- 二分查找
- 二维数组
- 动态数组
- 二叉搜索树
- 动态规划
- Big-O分析
根据您的背景,这份清单可能看起来微不足道,也可能看起来令人望而生畏。这正是关键所在。这些概念在面试中比在生产环境的 Web 编程中更常见。如果您是自学或毕业多年,并且不熟悉这些概念,那么学习它们会让您的面试表现更好。即使您已经了解这些内容,更新您的知识也会有所帮助。相当一部分面试问题都归结为广度优先搜索或使用哈希表来统计唯一值。您需要能够熟练地编写广度优先搜索 (BFS) 算法,并且需要了解哈希表的实现方式。
学习这些东西并不像我们交谈过的许多人担心的那么难。算法通常用学术语言来描述,这可能令人反感。但从本质上讲,这份清单上没有什么比现代 Web 应用程序的架构更复杂。如果你能(很好地)构建一个 Web 应用程序,你就能学习这些东西。我推荐的资源是Steven Skiena 的《算法设计手册》 。第 3 章到第 5 章以直白的方式很好地讲解了这些内容。它确实使用了 C 语言和一些数学语法,但解释得很好。Coursera 也有一些不错的算法课程。尤其是这门课程,重点讲解了面试中很重要的概念。
学习算法和数据结构不仅因为面试中会用到这些内容,还因为算法课程中解决问题的方法与面试中的方法相同。学习算法能让你进入面试的心态。
3.向面试官寻求帮助
面试官会帮助应聘者。他们会给出提示,回应候选人的想法,并引导整个面试过程。但他们对每位应聘者的帮助并不相同。有些程序员能够从面试官那里获得重要的帮助,而面试官却不会因此而责怪他们。而有些程序员则会因为任何提示而遭到严厉的评判。你当然希望得到帮助。
这归结于流程和沟通。如果面试官喜欢你的流程,并且你与他们沟通良好,他们就不会介意提供帮助。遵循一个谨慎的流程,可以更容易地做到这一点。我推荐的步骤如下:
- 提出问题
- 讨论暴力解决方案
- 讨论优化解决方案
- 编写代码
面试官问到问题后,首先要澄清问题是什么。这是需要严谨对待的时刻。澄清你能想到的每一个模糊之处。询问极端情况。提供具体的输入示例,并确保你对预期输出的理解正确。即使你几乎确定自己知道答案,也要提问。这样做很有用,因为它让你有机会提出极端情况并全面阐述问题(考察你如何处理极端情况是面试官评估面试表现的主要标准之一),也因为它让你在开始解决问题之前有时间整理思路。
接下来,你应该用你能想到的最简单的方案来解释这个问题。你应该直接讲,而不是直接开始写代码,因为这样讲起来更快,而且更能吸引面试官的注意力。如果面试官投入其中,他们就会介入并提供建议。 然而,如果你只是继续写代码,你就会错过这个机会。
求职者经常会跳过“暴力破解”这一步,认为问题的暴力破解方案太明显,或者错误。这是错误的。确保你每次遇到问题时都能给出解决方案(即使它需要指数级的时间,或者需要一台美国国家安全局的超级计算机)。当你描述了一个暴力破解方案后,问问面试官是否希望你实现它,或者提出一个更有效的解决方案。通常他们会建议你提出一个更有效的解决方案。
更高效解决方案的流程与暴力破解相同。同样,只说不写代码,并与面试官交流想法。希望面试官的问题与你见过的问题类似,这样你就能知道答案。如果不是这样,不妨想想你见过的最相似的问题,并向面试官提出这些问题。大多数面试题都是经典计算机科学算法的一些略显晦涩的应用。面试官通常会引导你找到这个算法,但前提是你已经开始了这个过程。
最后,在你和面试官都认可你的解决方案后,你应该开始编写代码了。根据公司不同,代码编写可能在电脑或白板上进行。但由于你已经想好了解决方案,所以这应该相当简单。为了加分,可以问问面试官是否希望你编写测试。
4. 讨论权衡
编程面试主要由编程问题组成,我目前为止就讲到这里。但是,你也可能会遇到系统设计问题。公司似乎更喜欢这类问题,尤其是对经验丰富的求职者。系统设计问题会询问求职者如何设计一个复杂的现实世界系统。例如,设计谷歌地图、设计社交网络或为银行设计 API。
首先,回答系统设计问题需要一些专业知识。显然,没有人真正指望你去设计谷歌地图(这花了很多人很长时间)。但他们确实希望你对这类设计的各个方面有一定的了解。好消息是,这些问题通常侧重于 Web 后端,因此阅读这方面的资料可以让你取得很大进步。以下是需要了解的内容(不完整列表):
- HTTP(协议层)
- 数据库(索引、查询计划)
- CDN
- 缓存(LRU 缓存、memcached、redis)
- 负载均衡器
- 分布式工作系统
你需要理解这些概念。但更重要的是,你需要了解它们如何组合在一起形成真实的系统。学习这些概念的最佳方法是阅读其他工程师是如何应用这些概念的。“High Scalability”博客是一个很好的资源。它发布了真实公司后端架构的详细分析。你可以阅读上面列出的每个概念在真实系统中的应用。
读完这些资料后,回答系统设计问题就变成了一个循序渐进的过程。从最高层级开始,然后逐层递减。在每一层级,向面试官询问具体要求(你应该建议一个简单的起点,还是描述一个成熟的系统是什么样子?),并讨论几种方案(运用你阅读中的想法)。讨论设计中的权衡利弊至关重要。面试官不太关心你的设计本身是否优秀,而更关心你是否能够谈论决策的利弊权衡(利弊)。好好练习一下。
5. 突出结果
你可能会遇到的第三类问题是经验问题。面试官通常会要求你谈谈你过去完成的一个编程项目。很多工程师在回答这个问题时常犯的一个错误是谈论一个技术上有趣的副业项目。很多程序员会选择谈论实现一个神经网络分类器,或者编写一个推特语法机器人。这些都是糟糕的选择,因为面试官很难判断他们的工作范围。很多候选人会夸大一些简单的副业项目(有时这些项目实际上从未成功过),而面试官根本无法判断你是否在做这样的事情。
解决方案是选择一个产生成果的项目,并突出成果。这通常意味着选择一个技术上不太有趣的项目,但这是值得的。提前想想你做过的、对现实世界影响最大的编程。如果你写过一款 iOS 游戏,已经有 5 万人下载,那么这个下载量就让它成为一个不错的选择。如果你在实习期间写过一个管理界面,并且已经部署到所有管理人员,那么这个部署就让它成为一个值得谈论的事情。选择一个实用的项目也能让公司知道你专注于实际工作。过于专注于有趣技术的程序员是公司会筛选的反模式(这些程序员有时效率不高)。
6. 使用动态语言,但提到 C
我建议你在面试时使用动态语言,例如 Python、Ruby 或 JavaScript。当然,你应该使用你最了解的任何语言。但我们发现许多人试图用 C、C++ 或 Java 进行面试,因为他们认为这些才是“真正的”编程语言。几本关于面试的经典书籍都建议程序员选择 Java 或 C++。至少在初创公司,我们发现这是个糟糕的建议。候选人在使用动态语言时会表现得更好。我认为这是因为动态语言语法紧凑、类型灵活、列表和哈希文字。它们是宽容的语言。这在编写复杂系统时可能是一个负担(一个备受争议的观点),但在试图将二分查找塞进白板上时,它非常有用。
无论你使用哪种语言,提及使用其他语言的工作经验都会很有帮助。公司筛选的反面案例是只懂一门语言的人。如果你只懂一门语言,你就必须依赖你在该语言方面的实力。但是,如果你用多种语言完成过工作或参与过业余项目,一定要在与面试官交谈时提及这一点。如果你使用过 C、C++、Go 或 Rust 等低级语言,谈论这一点会特别有帮助。
Java、C# 和 PHP 的情况比较棘手。正如我们在上一篇博文中所述,我们发现初创公司对这些语言存在偏见。数据显示,使用这些语言的程序员在面试中的通过率较低。这虽然不公平,但却是事实。如果您有其他选择,我建议您不要在初创公司的面试中使用这些语言。
7.练习,练习,再练习
通过练习回答问题,你可以大大提高面试水平。这的确没错,因为面试确实让人有压力,但压力会影响表现。解决办法就是练习。面试压力会随着经验的积累而减轻。经验积累越多,压力就越小。即使是在一次求职中,我们也发现求职者经常会在初次面试中失败,但随着自信心的增强,他们通过的次数也会越多。如果你难以应对压力,我建议你通过练习面试压力来快速应对。准备一份面试问题清单(《破解编程面试》这本书是一本不错的参考书),并解答它们。为每个问题设置一个 20 分钟的计时器,然后争分夺秒地作答。练习在白板上写答案(并非所有公司都要求这样做,但这是最坏的情况,所以你应该练习一下)。纸笔可以很好地模拟白板。如果你有朋友可以帮助你准备,轮流面试也是个不错的选择。阅读大量的面试问题还有一个额外的好处,那就是为你提供在实际面试中可以使用的思路。令人惊讶的是,很多问题都被重复使用了(全部或部分)。
即使是经验丰富(且无压力)的求职者也能从中受益。面试技能与程序员工作技能截然不同,而且可能会逐渐退化。但经验丰富的程序员通常(理所当然地)认为他们不应该为面试做准备。他们学习的时间更少。这就是为什么初级求职者在面试问题上的表现往往比经验丰富的求职者更好。公司深知这一点,而且有些公司却告诉我们,他们对经验丰富的求职者的编程问题设置了更低的门槛。
8. 提及资历
资历会让面试官产生偏见。Triplebyte 的求职者中,那些曾在顶级公司工作或就读于顶级学校的求职者,面试通过率比没有这些资历的程序员高出 30%(在我们这个不考虑资历的筛选中,以给定的表现水平为准)。我不喜欢这种做法。这不符合任人唯贤的原则,而且很糟糕,但如果你有这些资历,确保你的面试官知道这一点对你有利。你不能指望他们会看你的简历。
9. 排队报价
如果你读过给创始人的融资建议,你就会知道,让第一个风险投资公司(VC)给你投资offer是最难的。一旦你拿到一个offer,就会有更多的offer纷至沓来。工作offer也是如此。如果你已经拿到了offer,一定要在面试中提及。在面试中提及其他offer会严重影响面试官对你的好感。
这就引出了一个策略:列出你感兴趣的公司,然后按照兴趣倒序安排面试。尽早做好准备,可以提高你拿到理想公司offer的几率。你应该这样做。
结论
通过面试是一项技能。成为一名优秀的程序员固然有帮助,但这只是其中的一部分。每个人都会在某些面试中失败,而充分的准备可以帮助每个人通过更多面试。热情至关重要,而研究在这方面很有帮助。许多程序员因为缺乏热情而失败,就像许多程序员因为技术原因而失败一样。面试官会在面试过程中帮助应聘者,如果你遵循良好的流程并清晰地沟通,他们也会帮助你。练习总是有帮助的。阅读大量的面试问题并让自己习惯于面试压力,将有助于你获得更多的录用通知。
这种情况并不理想。准备面试是一项工作,强迫程序员学习除了开发优秀软件之外的其他技能会浪费每个人的时间。公司应该改进他们的面试流程,减少学术计算机科学、记忆事实和排练面试流程的偏见。这就是我们在 Triplebyte 所做的事情。我们帮助程序员无需看简历就能找到工作。我们让程序员从几个需要评估的领域中选择一个,并且我们会随着时间的推移研究和改进我们的流程。我们很乐意帮助你在初创公司找到工作,而不需要经历这些麻烦。你可以从这里开始。但现状就是这样。在这种情况改变之前,程序员应该知道如何做好准备。
感谢 Jared Friedman、Emmett Shear、Garry Tan、Alexis Ohanian 和 Daniel Gackle 阅读本文草稿。
[1]这并不是说面试表现与编程技能无关。两者确实相关。但这种相关性比大多数公司认为的要弱得多,而且除了编程技能之外的其他因素也解释了很大一部分面试差异。↩
文章来源:https://dev.to/triplebyte/how-to-pass-a-programming-interview-2g2k