这篇文章是专门为那些即将开始找工作的人写的。很多正在找工作的人可能会担心因为自己不是毕业于常青藤名校而无法在顶尖科技公司找到一份理想的工作。还有可能其他人会告诉你说因为你不够优秀而无法在微软或Facebook找到一份工作。但是我想告诉你的是,即使你不是出身名校,你依然可以在全球顶尖的科技公司找到一份你理想中的工作。下面我分享一下我是如何找到我梦寐以求的工作的。
这篇文章将主要包含以下几部分内容:
(1)我的个人背景。
(2)我是如何获得众多全球顶尖科技公司的面试机会的,这些公司包括Facebook、Amazon、LinkedIn、微软、Twitter、Pinterest、Snapchat和其他公司。
(3)我是如何拿到几家顶尖科技公司的软件工程师职位的Offer的。
(4)我从面试经历中学到的经验。
我的个人背景
我并非毕业于常青藤名校(常青藤联盟成员包括哈佛大学、耶鲁大学、宾夕法尼亚大学、普林斯顿大学、哥伦比亚大学、布朗大学、达特茅斯学院、康奈尔大学)。我在爱达荷州的一所社区大学读了两年书,然后在一所小型天主教大学拿到了计算机科学学位。
我是在大三的时候就开始学习计算机科学的,因为当时我觉得这门学科听起来非常有趣。在我成长的过程中,我拥有的的唯一一件类似电脑的产品就是超级任天堂的中国山寨版。甚至在当时,每次我放一盘磁带进去的时候,它都会崩溃。
为了在大学期间能够自力更生养活自己,我做了很多份的兼职。当我毕业的时候,我并没能很快就找到一份工作。我申请了尽可能多的大型科技公司的职位,并有幸获得了几次电话面试的机会。
当时我对technical screen电话面试没有任何概念,所以也就不知道该如何为这种面试做准备。我参加这些面试之前想当然地认为面试官可能会问我链表或者二叉树是什么这类面试问题。
在参加的所有几个电话面试中,我都没有通过。
勇往直前
我没有过多地探究自己是否优秀。我知道我的学习能力非常强。我需要的只是一个机会。正如大家所说的那样,要广撒网。而这正是我做的。
我接下来做了一件让我特别引以为傲的事情。我写了一个简单的Python脚本,它在Craigslist上抓取了一些含有一些关键字的职位列表,并在电子表格中收集这些职位的电子邮件联系方式。这并不是最聪明的解决办法,但在Craigslist上发帖的人对他们所要招聘职位的描述出奇地准确。然而,Craigslist并不喜欢人们抓取他们网站上的内容。为了解决这个问题,我通过一个VPN运行我的脚本,并有一个计时器,每隔几分钟就会暂停脚本。虽然它兵不完美,但却运行得很好。最后,我搜集了来自旧金山、波特兰、斯波坎和西雅图的公司的大约500封招聘电子邮件。我根据这些职位的具体发布时间和其它信息对结果进行了过滤,并通过添加越来越多的特性来改进它。后来我发现已经有一些机器人在爬Craigslist上的信息并发送自动电子邮件。这些公司大多是海外公司,它们希望将自己的公司推销给美国市场。
我采用的一个变通方法是,我精心制作了电子邮件,我在邮件标题里使用了那些公司发布的招聘信息里的一些关键词。然后,我在邮件正文部分添加了更多的细节信息,让邮件内容看起来更个性化。我做了一个快速的A/B测试,就这样,我收到的应聘公司的回复率从2-3%增加到了10%。
在发送的大约500封应聘电子邮件中,我收到了大约50份回复,其中一小部分给了我电话面试的机会。我之所以只发500封电子邮件,这是因为我时间不够,需要尽快找到一份工作。我会尽可能提高面试通过率,而不是获得尽可能多的面试机会。
幸运的是,我最终在西雅图的一家创业公司找到了一份初级软件工程师的工作。这家创业公司当时位于Kirkland,所以我必须坐45分钟的巴士才能赶上面试的时间。
在接下来的3年半的时间里,我一直在这家公司工作。我在那里学到了很多东西,比如亚马逊AWS、EC2、DynamoDB、SQS和Docker。我在这段时间里成长了很多。我学习了如何编写模块化的、可维护的代码,我学会了如何对软件设计进行推理,我也学会了如何处理人事方面的问题。
我周围全是一群聪明的人,他们有的在微软工作,有的在Amazon工作,有的在LinkedIn工作,我努力成为这群人中的一块“海绵”,我尽可能多地从他们身上进行学习,这对我的职业生涯产生了非常巨大的影响。
在创业公司工作的日子
我在加入的第一家创业公司工作期间,我做的几乎全部都是后台开发方面的工作,中间会涉及一些开发运维。我开始编写一些函数来添加或修改一个影响范围很小的特性,不过这是一个了解代码库并进行一些代码审查的好机会。一年之后,我开始负责代码库的一部分,然后我的任务是将一组特性转换为服务。这是这家创业公司SOA阶段的开始。我们开始将站点的各种组件转换为服务,我就是在这个过程中学习更多有关RESTful服务、身份验证、AWS服务、发布-订阅、分布式系统等方面的知识的。
有趣的是,我并不是通过书本或正规的教育来学习这些知识的。相反,是因为我在实际工作中需要开发完成一系列功能部件,但我在这方面存在知识瓶颈。所以我想,那就边学边做吧。很多时候,我都陷入了分析瘫痪状态,在这种状态下,我过度分析了各种情形场景,最终无法取得进展。
那些艰难的时刻其实是最好的学习机会。我开始学习功能范围、监视、警报和文档方面的知识。这个过程的每一步都揭示出我需要学习更多的东西。在过去的2-3年时间里,我成长地最快,无论是作为一个个人还是作为软件工程师都是如此。
我是如何准备面试的?
在经历了第一次求职面试中的各种艰难曲折后,我告诉自己,在未来的求职面试中我必须做好充足地准备。
我开始通过对我擅长的、不擅长的以及我可以改进的地方进行概述,从而为未来的面试做好充分准备。我将它分为三个类别:数据结构、算法和系统设计
我在自己的正式职业生涯中基本都是在PHP领域工作,在大学里也学过C++,所以我想尝试一些更简单、更不繁琐的面试。因为这个原因,我选择了Python。这是一门用来学习的非常好的语言,它很容易学习,支持许多开箱即用的数据结构,并且可以在白板上快速书写。我是通过Youtube上的一些视频教程学习Python的,并阅读了教学文档。另外,我选择学习Python的另一个原因是,它具有很高的可读性,而且在白板上书写很容易。这是C++和Python之间的一个简单的比较:
下面是用C++语言写的降序排序:
下面是用Python写的版本:
我积累的经验的是,很多应聘者在面试过程中会在简洁方面犯错。在45分钟的面试中,你需要用大部分的时间来解决实际问题。
黄金小建议:选择一种不那么冗长的语言,这样你就可以在白板上更快地写代码了。
面试准备模式
我花了大约一个星期的时间在LeetCode、HackerRank和Project Euler中做了一些简单的测试挑战,以便熟悉它们的接口,并让自己开始习惯用Python编写代码。
第一周我了解了我在某些编程语言方面的能力水平。我又花了一周时间来进行一些设计上的挑战,并尽可能做到深入和广泛。
这对我来说是非常有趣的,因为我经常查看iOS应用,并试图弄清楚它们是如何做到的。例如,你如何从头开始重新开发Instagram?(我在Facebook面试时曾被问到这个问题)。我的专业背景是API设计和服务导向式架构。因此,我借此机会展示了我将如何设计我自己的Instagram版本。因为我在一些业余项目中积累了一点iOS应用编程经验,所以我在回答这个面试问题时可以稍微讲一下回调函数等方面的内容。我一开始讲的是我想在我自己的Instagram版本中加入的一些功能:赞、上传照片和简单的时间线。功能范围使我能够构建一个非常可靠的API,因为我非常了解这些场景。然后我画了一些概要设计图片,介绍了客户端机如何与后端交互,以及后端如何存储
数据。
我从小处着手,然后在需要的地方添加更多的组件,并主动寻找瓶颈所在。我做了一些有根据的猜测(而非盲目的猜测),以及每一项技术是如何融入进去的的。同样重要的是,什么技术无法很好地融合进去。例如,为什么要使用Cassandra而非MySQL来存储某些信息,为什么要使用OAuth而不是通过简单的认证,是使用Cassandra还是Memcached来缓存数据,是使用流媒体还是批处理处理等等。
在这里,你需要探索的领域还有很多。因此仅仅通过一个小时的沟通是不够的。为了能够更好地回答这类面试问题,你必须阅读并学会权衡取舍。一个行业的技术优势和劣势是什么。为此,我推荐一个网站:HighScalability。
回答这类面试问题时,要做到就像和同事进行一次典型的头脑风暴一样,做尽可能广泛和深入地探索。你要知道,这些设计面试的目的是要了解你的知识面有多广,以及你了解的有多深入,这是一个让你脱颖而出的机会,这一点很重要。我在Youtube上看了一段关于如何解决设计问题的视频,它给了我深刻的洞察力,为我在回答设计类面试题中提供了巨大的帮助。我从中学到的两个主要经验是:推动设计对话、展示你所知道的。
我列出了自己在下面这些领域里的能力水平:数据结构(链表、散列映射、二进制树、二进制搜索树、堆、数组)、算法(二进制搜索、哈希、动态规划、排序)和特定语言的语法和库(例如,Python的lambda、附加和索引)
我选择了我最不擅长的领域,并开始研究它:算法。算法从来都不是我的强项。我大学毕业已经有一段时间了,在我的日常职业生涯中,我没有花太多时间在二进位搜索上。我对每个算法的运行原理在使用场景一个初步的了解,但我无法在10分钟内写出二分查找程序,不管是在白板上还是在面试官面前都是如此。
我买了一堆精美的细马克笔,效果非常好。但在面试室里的马克笔通常都不好用,我通常在面试室里会花2-3分钟找一支能用的笔,而这2-3分钟是你浪费不起的。另外,细马克笔允许你在一个典型的白板上写5-8行代码。
黄金小建议:自己准备一盒马克笔。
我从Costco花了50美元买了一块白板,从亚马逊买了一些相关书籍,然后开始了我的编程实践。我确保我在二分查找、递归、动态规划、BFS和DFS上做了专门的提升练习。很多的面试问题都是围绕递归和二分查找展开的。我所见过的最好的面试问题是那些有很多不同解决方案的面试问题。
在参加Google的面试中,我曾被问到一个与文件系统目录有关的问题,以及如何遍历这些目录(提示:递归)。我很快就解决了这个问题,然后面试官问了如何在那个目录中找出一个丢失的文件。这个问题相对更难一点,但是我还是解决了。然后我们讨论了如何重建目录,如何对它进行序列化和反序列化,我们花了大量的时间讨论文件目录在底层是如何运行的。对我来说,这是一次非常愉快的面试。
参加顶尖科技公司的面试
可以这么说,参加这类面试是一次令人神经崩溃的经历,给人的感觉如同做过山车。
我是根据下面这个方式来分配我的时间的:20%的时间用于简历制作,20%的时间用于调查研究,60%的时间用于面试准备。
我将自己20%的时间都用在整理自己的简历上了,而我的简历至少有三年时间都没有更新过了。我仔细研究了我过去做过的所有事情,并选择了一些我从头负责到底至的项目,不用考虑项目的复杂性如何。
我之所以会这么做,主要有两个方面的原因。从头到尾负责一个项目需要纪律和领导能力,这是我想向面试官重点突出的两个能力。其次,对于那些我从头至尾负责的项目,我可以向面试官深入且广泛地描述项目的各个方面。这一点在我参加Twitter的面试时回答有关设计的面试问题时发挥了重要作用,在Twitter的面试中,面试官不仅对我负责的项目的设计工作进行了严格的考察,而且还对背后的决策进行了考察。
我会将20%的时间用于调查研究。这里说的调查研究是指对我感兴趣的公司进行尽职调查,并寻求内部推荐的机会。通过内部推荐的方式能够大大提高求职信的回复率。根据我自己的实际经验,我向20多家创业公司和中等规模的公司发送了求职cold message,只有少数几家公司回复了。但是如果得到对方公司内部员工推荐的话,那么对方公司几乎都会在一周时间内内给我回复信息。
我并不善于交际,我认识的能将引荐给我感兴趣的公司的人其实并不多。为了解决这个问题,我会经常使用LinkedIn。LinkedIn里有一个搜索功能,我经常用它来搜索1 度联系人和2度联系人。所谓1度联系人,就是通过接受邀请直接建立联系的会员。你可以查看他们的个人档案和人脉信息,不受限制地向对方发送站内信,还可以在你的个人首页看到对方在领英的动态消息。所谓2度联系人,就是已经与你的1 度联系人建立联系的会员。通俗理解就是你好友的好友,一般是没有建立直接联系,但和你可能有交点的人群。免费账户可以看到2度人脉的个人档案,可以看到和对方的共同联系人,但不可以直接发站内信。
LinkedIn的搜索功能
这是非常重要的,因为给一个人你不认识的人直接打求职电话是非常困难的。当接到不请自来的陌生人打来的电话时,人们通常都非常谨慎,通过这种方式很难很快建立信任关系。LinkedIn在我调查研究阶段对我的帮助非常大。
回顾我面试过的所有公司,以下是我对每一家公司的看法:
Facebook/Google:很机械化。标准的面试流程,我和这些公司无法建立任何情感连接。
Pinterest:在这家公司的面试体验并不是最好的,但这家公司是一个很酷的公司,产品也是很酷的产品。
微软:我非常喜欢我所面试的团队,尤其是团队经理。标准的面试问题,但是非常个性化。是我的第二选择,当然这个因人而异,微软每个团队的面试风格是各不相同的。
Amazon:标准的面试流程。大概有50%的人会喜欢这种面试风格,也有大概50%不喜欢这种面试风格。
Twitter:面试流程非常有趣和个性化。我个人非常喜欢它的面试流程,非常重视个人和我过去做过的事情。
Snapchat:在洛杉矶有非常酷的办公室,有很多人都决定在创业的大潮中加入其中。
Lyft:离我住的地方不远,办公室很不过,标准的面试流程,我对这家公司没有太强烈的感觉。
下面分享一下我最喜欢的一家公司及其面试流程
从很多方面来说,我认为要通过Twitter的面试都是非常困难的。但与此同时,Twitter的面试流程比我面试过的其他任何公司都更有趣、也更个性化。
Twitter的面试流程大概是这样的:与一个工程经理进行简单的介绍性电话面试。接下来是一到两轮的技术电话面试,这取决于你的表现。如果通过电话面试,他们会把安排你到应聘工作地点进行现场面试,我是在西雅图参加的现场面试。一共有3轮1小时15分钟的现场面试,每场面试都有两个面试官。
最开始的两轮电话技术面试都是标准化面试,你需要在一个共享的编码文档中通过编程来解决实际的问题。
现场面试更像是一种双方的互动交谈,也不会让人感到太害怕恐惧。面试官会问你一些关于你过去参与过的项目的深度问题,他们会询问你过去做过的事情。如果你过去曾负责过一个项目,那么面试官就会问一些有关这个项目的问题。面试官鼓励你用这些项目作为参考,并从中来试探你的想法。
其它公司的面试感受
相比之下,我觉得Facebook和Google的面试更加机械化。他们有1-2轮的技术电话面试,5到6轮的现场编码考核。每一轮面试都需要你在白板上进行编码,还要要求你在一个相对合理的时间内完成一个近乎完美的解决方案。
Facebook有两轮编码面试,一个设计面试,一轮行为面试。在一天面试快要结束的时候,我又参加了一轮shadow面试((即老员工面试,自己旁听),这部分面试并没有计入我的面试总分。
Google有5轮编码面试,没有一轮有关设计的面试,期间没有一位面试官问我之前做过的项目。虽然我并不认为这是一种糟糕的面试方法,但这种面试让我感觉太机械化了,并没有给工程师提供多少机会来展示他们的能力。有些人在这种面试中表现得非常好,就像有些学生在考试中表现优异一样。
我并不是喜欢在Pinterest的面试体验。我认为Pinterest这款产品本身非常有意思,他们的工程技术团队似乎也在解决一些非常酷的技术问题。但是我在Pinterest的面试体验却是非常糟糕的。
Pinterest有三轮编程面试、一轮设计面试。在这4轮面试中,设计面试是最让我失望的。为什么这么说呢?面试官迟到了,他花了几分钟时间在我浏览了一下我的简历,然后开始在白板上画一些API。他简短地描述了他期望API做什么,并问我该如何解决这个问题。我们阐明了API的特性,然后我开始使用白板描述我的解决方案,大概5分钟后,我转过头发现他竟然睡着了。这次面试体验太糟糕了。我在一项调研问卷中向招聘人员反馈了这个问题,但是没有收到任何回复。
我就不详细和大家分享我在面试中被问到的所有问题的细节了,不过我想和大家分享我在准备面试的过程中学到的一些经验和有用的技巧。
我学到的东西:
(1)简历内容一定要做到实事求是。大多数公司的面试官会问你一些关于你的简历上的内容的问题,面试官通常能够根据你的回答很容易判断你是否在简历内容上作假了。此外,对一个项目做到100%的了解要比对10个不同项目有10%的了解要好得多。
(2)简历最好只用一页。对于科技公司来说尤其如此,因为科技领域有一个普遍的共识,只有当你有博士后的研究经历或者亲自深度负责过很多项目,这时你的简历有2页或更多页才是合理的,否则最好用一页。
(3)多出去社交并建立一个自己的人脉网络。软件工程师职位的竞争非常激烈,这些顶尖的科技公司每天要筛选成千上万份简历。如果你应聘的公司内部有员工帮你引荐,那么你的简历被关注的可能性会更高。
(4)精心准备面试内容。每一个对你感兴趣的公司都想知道你为什么对他们感兴趣。一个糟糕的回答是:我现在急需找到一份工作帮赚钱支付账单。一个不那么糟糕的回答是:我在网上浏览,发现了你们公司,好像你们在做一款非常有趣的产品。一个很好的回答是:我知道你们公司在X领域做了一些有趣的工作来实现Y。我在过去做过一些工作,这是我学过的关于A、B、C的知识,这些知识可能与X领域有关。我对Y非常感兴趣,因为......(不要将这当作一个固定的模板。相反,你应该从中找到模式,——做充分的调查研究,向你应聘的公司展示为什么你和这家公司是非常匹配的。)
其它一些建议
技术面试是非常困难的。然而,最好的机会是留给那些准备好的人。
(1)早做准备,而且要做充分地准备。每个人都知道他们应该为面试做准备,但大多数人都不知道如何才能真正做好准备。就像任何值得做的事情一样,需要刻意练习才能在某件事上有出色得表现。而刻意练习意味着你需要有一套系统。
(2)建立一套用来练习技术技能的系统。我会根据1-10分的评分方式对自己的表现进行评分,并努力提升我自己最不擅长的领域。我花了好几天时间研究不同类型的面试问题,直到我完全掌握了每个概念。我每天都在Evernote上做笔记,笔记内容包括编程技巧、常见错误和误解、用于解决特定问题的框架等等。
我的Notebook
(3)将你掌握和学会的知识记在本子上。我同时使用Evernote和OneNote来记录和追踪事情。我用OneNote来记录技术方面的内容或代码,因为我可以按照我喜欢的方式来对这些笔记进行格式化。我用Evernote主要写一些文章或感想。上面的图片显示的是我在架构和系统设计上的一些想法。
Evernote主要用于记录想法/技巧
(4)把所有的事情都记录下来,即使你认为你不会用到它也要记录下来。我非常健忘,所以我会将我学会的任何东西都记录下来,包括shell命令。我会时不时地阅读技术博客,如果我发现任何有趣的东西,我都会立刻在Evernote上将其记录下来。我会每星期或每月对记录过的内容做一次整理优化。这个习惯在我的职业生涯中对我的帮助很大。
(5)模拟面试。这绝对是非常有价值的,我极力推荐大家这样做。我会和朋友一起进行模拟面试,并尽可能多地练习。如果你找不到朋友一起练习模拟面试,那么我推荐你使用Refdash,这是一款“面试即服务”的产品。这个平台上有一群在Google、Facebook和微软等大型科技公司工作的面试官。这些面试官会评估你的编码和设计技能。最重要的是,在每次模拟面试后它都会给你打出一个分数,并给出一些具体可行的改进方法。
(6)允许自己失败。在我整个应聘过程中,我经历过很多次的失败。有时失败只是因为你运气不好。即使你面试失败了,这对你来说也不是世界末日。公司在招聘的过程中倾向于说“不”,因为这对他们来说风险更低。从长远来看,犯假阳性的错误比假阴性的错误的成本更高。最初的几次拒绝给人造成的打击最大。当我刚开始面试的时候,我几次电话面试都没有通过,我的自信心也受到了严重打击。我对自己的能力也开始心存怀疑,并开始担心自己的技能在当今的就业市场中已经不受待见了。然而,我给自己支了一招:如果你失败了10次,那么再多尝试10次。你所需要的只是一次成功,这种安慰给了我很大的信心,让我能够不断尝试,当我拿到第一个Offer之后,后来的其它Offer来得就会容易很多。
我花了大约两个月的时间来为我的面试做准备和并做各种模拟练习。我每周大概会在这方面花20个小时,或者每个月花80小时,在全职工作之余进行学习和记笔记。
为了充实我的简历,我花了3年半的时间去专心刻意地工作。在日常工作中,我会有意识地选择那些困难棘手的工作,这样我就能比其他人学到更多东西。尽管我并非毕业于常青藤名校,之前也没有在顶尖科技公司工作的经验,但我对我所负责过的项目有一个清晰透彻的理解,并在简历中体现出这一点,从而让自己在面试中能脱颖而出。这是有可能做到的,因为我做了很多研究,并将我学到的所有东西都记录了下来,并建立一个用来练习技术技能的系统。
要记住:坚强的人能够生存,坚韧的人能够茁壮成长。
小结:不要放弃,为机会而时刻准备着,多练习,并始终怀有希望。专注于过程,并在整个过程中采用严格、专门的方法。
我推荐的书籍和工具:
书籍《Elements of Programming Interviews: The Insiders' Guide》 :对解决那些非常难的编程问题非常有帮助。
书籍《Cracking the Coding Interview: 189 Programming Questions and Solutions》:很好地覆盖了基本的CS知识。
OneNote:我使用这款工具来存储所有的代码片段。
Evernote:我使用这款工具来记录存储其它所有东西。
CodeRunner:我非常喜欢这款Mac应用,我曾多次使用它来运行特定的Python脚本和函数,而且效果非常好。
Jobscan:我听说过很多关于它的很酷的事情,建议你试试它的简历筛选工具。
Refdash:由一群前Google员工运营的产品。用这款产品来模拟面试的效果非常赞。我在Refdash上碰到的面试官曾在Google工作过,他为我指出了很多我应该关注的地方,以及Google面试的主要评分依据。我强烈建议你尝试一下。
CodePath:一个帮助人们进入科技行业工作做准备的非盈利组织。公司的两位负责人Tim和Nathan都是很棒的人,我从他们那里学到了很多。这个社区非常有帮助,每个人都愿意伸出援手。