跳槽拿了7个senior offer,分享一下经验

avatar 764814
newgpu
142388
305
在匿名区发帖没有人看,遂在这里重新发一下。

楼主最近跳槽面了一堆公司,最后拿了7个senior offer,分享一下经验,同时希望能鼓励那些同样被准备跳槽折磨得痛不欲生的战友们。先说一下面试各个公司的结果:
  • Facebook: E5 offer
  • Databricks: senior offer
  • TikTok: 2-2 offer
  • Apple: ICT4 offer
  • NewsBreak: senior offer
  • Lyft: T5 offer
  • Instacart: L6 offer
  • Confluent:onsite表现不够好,说只能降级给offer,于是我没继续谈offer了
  • LinkedIn: 电面过了,onsite被我取消了(因为recruiter在onsite前一天通知我onsite被安排在连续的两个半天了,但是我LinkedIn面试后面那天已经安排了Facebook面试)
  • Amazon: 电面过了,onsite被我取消了(因为recruiter回复太晚,onsite安排得太晚了)
  • Uber:onsite挂了
  • Robinhood:第二轮电面挂了(就是system design那轮,job scheduling system)
  • Netflix:recruiter回邮件约电面的时候我已经拿了几个offer了,遂拒
  • Pinterest:recruiter发邮件的时候我已经拿了几个offer了,邮件里告知我简历被拒了(哈哈哈)


以上只有Netflix和Pinterest是网申的,其他都是内推的,所以还是内推靠谱。具体每个offer的数字就不说了,大概跟地里相同offer的最高数字差不多。

时间线
  • 今年二月底开始准备跳槽,然后整个三月在准备系统设计
  • 三月底开始找朋友内推,在一个星期内把内推和网申都弄完了,三月最后一周在刷题
  • 电面全部安排在了四月的前三周,所以四月我一边刷题一边在电面,所幸所有的coding电面都过了(只有Robinhood系统设计电面挂了),电面完了之后立刻继续准备系统设计
  • onsite全部安排在了五月的中间两周,这时候基本不刷题了,每天都在看系统设计。其中我有7个onsite安排在了连续的7个工作日(其中有周一到周五连续5个onsite的成就),那酸爽,只有玩过的人才懂。每天onsite完了之后脑子一定是又晕又疼,要躺下睡30分钟才能缓过来。晚饭后要接着准备第二天的面试。
  • 从五月下旬开始就陆续出offer了,六月初基本就完成了offer的谈判。最后去哪里我就不透露了,也请大家不要问,谢谢。


个人背景
从我面的公司应该可以猜出,我现在在某大厂。硕士毕业就一直在这个厂里,现在是senior level。四年期间主要做的是ML相关工作(算是所谓的MLE?),在产品组做ML工作刚开始觉得很有意思,后来就觉得有点无聊,特别是升到senior以后觉搞model是绝对升不到下一级的。但是我平时做项目的同时,对周边其他组的东西也比较了解。在做ML工作的同时,对ML infra那个组做的东西也比较了解。于是我花了精力把简历包装成“带有ML背景的backend eng”,但是我实际是MLE。但是由于我平时花了功夫了解别的组的东西,后来面试的时候别人问我ML infra方面的东西我也能答得上来,其实他们没问得很细,如果再问细一点我可能要被难住。但是既然决定去面backend岗位而不是MLE的岗位,我的系统设计就得从零开始学。因为MLE的系统设计对我来说其实是很简单的,毕竟我干了四年,但是backend岗位的系统设计我完全不会,因为在大厂产品组干四年,都是用别人搭好的现成infra,如果自己不有意去读别人的文档和代码,很可能啥也学不到,只学会“什么情况该找哪个组,调用哪个接口”。但是大厂都是impact driven(特别是产品组),公司才不在乎你学到了多少技术,学习别人组(特别是核心组)的技术只能提升技术水平,如果那个组离你太远,学这些东西对升职是没有帮助的。所以我在准备面试的时候也集中读了一下几个核心组的文档。

Coding面试
Coding面试应该是最容易准备的,我由于本科打的基础比较好,就没有花很多时间。我用了差不多两周的时间集中准备coding面试,基本就是买个LeetCode会员,然后随机做一些题。我最后做的题目一共不到100道,但是看的题目应该有400道。后面为了省时间,看完题目如果觉得肯定会做,就直接跳过了。

关于Coding面试,刷题当然是很重要的,但是面经也很重要(感谢地里分享面经的人们)。我在临近每个面试的时候,都会把地里的相应公司的面经翻出来,每道题都亲手写一遍,面试的时候确实遇到了不少原题。刷面经比刷题性价比要高太多了。

关于面试时候的编程语言,我一直都是用Python,因为Python写起来就是快,语法糖多,导致一行代码可以实现其他语言几行代码要干的事。我把Python的一些对刷题有用的语法总结了一下,附在了附件中。

Behavior面试
Behavior面试我基本没有花时间准备,我只是看了一下亚马逊的“15 leadership principles”,然后每一个对应准备了一个故事。由于我当过几次behavior面试官,所以我知道一般情况下面试者是如何被评价的。面试官的重点就是从面试者的回答中挑出得分点,而面试者的重点就是踩点。对于面试者来说,一般听完题目就能大概知道这题要考什么点,然后快速在大脑中搜索出来准备好的故事就行了。有时候我们经历的事情比较复杂,所以需要花比较长的时间讲故事背景,但是面试的时候一定要注意,压缩故事背景,力求简单明了,因为重点不在故事背景,在于你在特定情况下你扮演了什么角色,采取了什么措施,得到了什么结果。每个故事最后一定不要忘记强调结果,如果没有结果你编也要编出一些正面的结果。有的人喜欢花很多时间把故事交代清楚,然后没踩到点,这时候面试官一般会问follow up问题,引导你去踩点,如果你依然踩不到点,面试官很可能放弃这个问题开始问下一个。所以大家一定注意保持故事不要太长。关于面试要踩的“点”,一般都是常识性的点,比如“你能不能合理处理跟同事的矛盾”,“你是否关心你的产品的用户”,“你是否能在复杂的情况下做出技术决策”,“作为TL,你是否能帮助junior工程师成长”等等,所有的问题都是稍微拐个弯问这些点。基本上所有的点逃不出亚麻的15个principles。当然,如果你面试staff以上的岗位,可能会有关于管理方面的问题,我面试senior岗位就没有这种问题。

系统设计面试
系统设计面试是我要着重说的,因为我本身算是MLE,对于系统设计是从零开始准备的。我在三月份大概花了三周的时间把DDIA(Designing Data-intensive Applications)这本书看了一遍,然后四月把grokking(grokking the system design interviews)看了一遍。当时我觉得自己简直无敌,然后去面试Robinhood的第二轮电面(job scheduling system那道题)就挂了。那是我人生第一次系统设计面试,也是我这次这么多轮面试第一次挂在电面上,对我打击很大。特别是我提前刷了面经,知道了他们大概率面这道题目,提前把公司内部的job scheduling那个组的文档和论文都读了几遍,对于这个系统可以说是了如指掌了,但是面试依然挂了。

当时我就意识到一个重要问题:系统设计面试,技巧也很重要。面试技巧只能在实战中学会。于是我幡然醒悟,在一个付费模拟面试的网站(interviewing.io)进行了4次系统设计模拟面试。每次模拟面试完了之后,面试官会立刻跟你反馈,hire还是no hire,问题在哪里。只有这种即时反馈的模拟面试,才能真正让你的面试技巧得到提升。我当时第一次模拟面试就拿了一个weak hire at senior level,面试官给我的反馈就是对面试节奏把握不好,达不到一个senior的要求,这个一会儿我会详细说。

在那个面试官花了十分钟教我如何把握面试节奏之后,我变质了。我像是打开了任督二脉一样,突然意识到了,在花了那么多时间看书看资料练习内功之后,如果把功力在面试的时候表现出来也很重要。于是我给自己定了一个系统设计面试套路,后面的面试都坚持那个套路,同时根据面试官的风格不断调整,做到始终掌握节奏。后面的三个模拟面试,拿了两个hire一个strong hire at senior level,因为我花了那么长时间看DDIA和grokking,我不缺内功,我只缺面试技巧。

下面我来分享这个我自己总结出来的系统设计面试套路,特别是针对senior level。因为senior的系统设计面试,很多公司会要求面试者能主导整个谈话(drive the conversation)。
  • 面试官把题目说出来以后,问问题,搞清楚需求。需求就分两种:functional requirements 和 non-functional requirements。对于functional req,要根据题目适当地问问题,了解需求。对于non-functional req,基本就是在以下的需求里面挑选出合适的:usage pattern(是read heavy还是write heavy),是否需要考虑scalability的问题,是否需要highly available,consistency(strong consistency,还是eventual consistency,是否需要read-your-own-write consistency),latency是否有要求,data durability是否有要求,idempotency(对于付款相关的系统一定强调这个)。以上有那么多non-functional req,我们不可能对于每个问题都把每个需求说一遍,那样太浪费时间。我们应该关注这个系统的重点,比如让你设计monitoring system,那availability就是重中之重,其他的点比如scalability,虽然重要,但不会是考察的重点,可以这时候简单提一下,在面试的后期再回头讲解如何解决这个问题。functional requirements 和 non-functional requirements应该力求在15分钟以内说完。有些点快速略过很重要,有时候你说的不是重点,虽然说了不会扣分,但是会耽误几十秒时间,使得后面没有时间说重点。系统设计面试,时间管理非常重要。
  • 在搞清楚需求之后,对于senior面试者,一般都是希望你从这里开始一直主导对话直到结束的。所以我会直接说"okay now let me list a few topics that we wanna cover",然后直接写下"API design", "capacity estimation", "high-level architecture design","database (schema, sql/nosql, sharding, replication)"和"other topics"。这些就是系统设计可能会讨论的大方面,提前写好可以保证你在主导对话的同时记得涵盖所有的点,不然自己一直说,可能一兴奋忘了说重点。列出这些点之后我会说"now let's start with API design, what do you think?"然后面试官就会回答好或者不好,你就可以继续说下去了。这里要注意的是,我们其实只是在假装"drive the conversation",最后先说哪个再说哪个其实还是面试官决定的,除非在少数情况下面试官没有偏好,告诉你先说哪个都行,那你就可以自己随便挑。注意,如果面试官让你自己挑顺序,你也要按照合理的顺序,或者让自己最舒服的顺序,来最大化自己的收益。下面具体说说买个方面应该怎么应对。
  • API design。如果这个系统会暴露出一些API,那么一般这是个考察重点。在说这个主题的时候,一般都是对于每个API,定好名字,定好输入是哪些,输出是哪些就行了。有少数情况面试官会问你是用RPC还是Rest API,有的还会问一些Rest API的知识,这些都准备一下就行了。有的情况下设计synchronized API和asynchronized API会有很大不同,那么就要说清楚你选择哪个,以及理由是什么:比如有的时候一个操作需要执行很久,这时候一般选择设计一个async API先立刻返回一个id给caller,让caller拿着id去查询操作的执行情况,而不应该只设计一个sync API让caller一直阻塞在那里。有时候一些API看起来是读东西的,所以不需要任何输入,这时候需要注意,就算不需要任何输入,也需要一个id来识别caller,因为有时候要做rate limiting,这个在面试的时候随便提一下就可以了,真正如何做rate limiting可以放在最后"other topics"里面说。
  • Capacity estimation。这个简单,grokking里面讲得不错了。一般就是把QPS (read, write),network bandwidth(upload, download),disk storage算一下就行了。注意,算QPS和bandwidth的时候,要把average value和peak value都算一下,一般是先算average,然后你可以说假设peak比average高一个数量级。1M/day换算成QPS就是12/s,这个要记住。算disk storage的时候,直接说“假设我们存5年的数据”,因为5年约等于2000天,好算,同时不要忘记存在disk上的数据都有replication,一般直接说"let's assume the replication factor is 3",然后乘以3就行了。
  • High-level architecture design。这个就是画图,没啥好说的。建议提前熟悉一下面试要用的画图软件。
  • Database (schema, sql/nosql, sharding, replication)。一般讨论数据库的时候就是讨论这些点,说schema的时候一般说一下有哪些表,每张表有哪些column,谁是primary key就行了。对于sql/nosql,要根据场景来说,我遇到的只能用sql的场景很少,只能用nosql的场景也不多,一般都是二者都可以,但是我会跟面试官说虽然二者都可以,但我更偏向于nosql,因为这里写操作比较多。但是大家还是要根据具体情况来,比如订票系统,牵扯到多张表的distributed transaction,那么只能是sql,还有购物相关的系统,user-order-item这些东西是天生relational的,那么sql也是更好的选择。我印象中的其他系统就很少遇到那种只能用sql的。对于sharding,一般都有一个"shard by user id"还是"shard by item id"的trade off,如果是user id,那么会有Hotspotting问题(因为有的user特别活跃),如果是item id,虽然可以解决hotspotting问题,但是如果需要读某个user的数据,就需要访问所有的shard。这个trade off对于大多数题目都适用,如果是你在讲database的时候主动提出,会大大加分。
  • Other topics(cache/how to scale/push vs. pull/monitoring/rate limiting/failure handling/logging)。如果以上所有东西说完还有时间,一般面试官会让你在这里面挑一两个点讲一讲,就挑最拿手的讲就行了。注意,有时候这里面的某个点会是这个系统的重点,那么就应该把这个点放在前面着重讲。


以上就是我总结出来的套路,但是一定要注意在面试的时候根据面试官风格的不同适当调整。技巧就是每次都先问问面试官是不是ok,比如"let's start with capacity estimation, what do you think?",有的面试官压根就不希望你做capacity estimation,会告诉你先不要做,后面有时间再做,那么这个技巧就可以帮你节省大量的时间。有时候有的面试官自己有强烈的偏好,会告诉你先画high-level architecture,然后等你画完不给你机会自己说,而是开始问问题,不给你机会drive the conversation。我面了这么多家,各种风格的面试官都遇到过,最后得出来的体会是:这个套路可以应付大多数面试,但是一但发现面试官有自己的偏好,就一定要放弃套路,跟着面试官走,有的面试官完全不需要你来drive conversation,你就让他问问题就好了。有的面试官在你说话的时候绝对不会打断,所以你要不断确认你说的是否合理,不然花很多时间说一些面试官根本不在乎的东西,虽然不扣分,但是浪费了宝贵的时间。对于大多数传统的面试官,根据这个套路就能应付。

面试技巧固然重要,内功也不能忽视。我在准备阶段主要接触了以下资料:
  • DDIA:这是我一开始准备就开始看的书,我觉得有条件的应该看两遍,开始的时候看一遍,然后进行一些面试练习之后再看一遍加深印象
  • grokking:这是我看完书之后就看的资料。很多人说这个资料不行,但是我觉得这取决于你如何对待它。它的问题在于讲东西的时候有时候没有章法,很多时候没有列出重要的trade off。但是它的价值在于给我们准备了很多常考的例题,每个例题都踩了一些点。如果我们能合理组织它踩的这些点,还是可以应付面试的。最大的价值还是它提供的例题,基本都是面试中常见的题型。
  • YouTube上的InfoQ频道:看这个频道里的QCon视频,可以真正了解工业界对某些问题的解法是什么样的。看多了之后会增加你在面试的时候的自信:因为你知道你说的就是工业界常用的解法,绝对不会错。这个建议没事就看看,像看剧一样刷。
  • YouTube上Scott Shi的频道:这个频道最大的意义也是给大家提供了一些常见的例题(还有一些不常见的例题)。如果纯看视频里讨论的质量,肯定没有那么高,但是关键在于这些例题以及这些讨论能不能引发你的讨论,你能不能把这些题目自己模拟做一遍。

如果以上的资料都看完了,后面的重点就是练习面试技巧,我采取的是付费模拟面试的方法,大家可以采取别的方法。重点是一定要实战练习,让自己习惯面试的环境。

Offer谈判技巧
这次跳槽谈offer的过程中,发现很多recruiter喜欢问我的compensation expectation,所以我们从这个话题开始聊起。如果是面试之前或者出结果之前问我comp expectation,我肯定是打哈哈过去了,我就说“不知道没想过,等面试结果出来再说”。但是有几个recruiter在出结果之后,出offer之前也问了我expectation,这时候打哈哈就不太好用了,有的recruiter一定要让你说一个数字才肯去谈offer。那么这时候就有如下方法应对:
  • 如果你现在的TC比较高,可以给出现在的TC,让recruiter至少给到这个数字(如果你TC低就不要说出去了)
  • 如果你已经拿到了其他offer,可以说“我没有具体期望,但是我希望你们可以beat其他offer”,然后告知他其他的offer
  • 如果你啥也没有,就只能硬聊,那么可以参考一亩三分地上的最大的包裹,然后加一点钱告诉他那就是你的期望,反正他们大概率给不了那么多,就可以讨价还价。
  • 如果你真的不想说自己的期望,可以一直绕圈子,说“我真的不知道现在市场怎么样,请问你们能不能先给一个offer”,但是很少有能让你糊弄过去的recruiter。

第一轮的谈判要点就是绝对不要透露自己真正的期望,同时尽可能拿到比较高的初始offer。所以对于你最想去的公司,一定要留在靠后的位置,已经拿了很多的competing offer之后再开启初始谈判。有时候某个公司出结果比较早,但是你又比较想去,你可以说“我现在还暂时没有期望,能不能等我拿到其他offer告诉你”,然后你就可以拖到你拿到一些competing offer之后再开启谈判。一般的公司都不能来回很多次的,所以对于特别想去的公司,要力求在第一轮就让他们给出比较好的offer。一般的公司都不会给你很多轮谈判的机会,所以我珍惜了每一轮的机会,我对于最想去的公司,在谈到一个不错的价格之后,直接使出了最后一招:给到多少就签字。这个就是你的底牌,说出这句话就意味着这就是最后一轮谈判了。而且这张牌也只能对最想去的公司说。这个只是在一个已经不错的offer基础上再加一点钱的方法。我最后靠这个方法拿到了out of band的数字。

总结
写这篇文章真的太累了,所以最后有些虎头蛇尾。offer谈判没有说得很详细,说实话我这方面经验也不是那么丰富,大量参考了之前一个老哥的offer谈判的帖子。最后祝跳槽的各位好运!

补充内容 (2021-06-08 12:25 +8:00):
那个Python的笔记忘记放在附件中了,分享一个地址:drive.google.com

补充内容 (2021-06-08 12:26 +8:00):
那个Python笔记是HTML格式,需要下载下来用浏览器打开

补充内容 (2021-06-08 15:58 +8:00):
那个Python笔记是我四年前毕业前写的,为了当时刷题准备的,所以都是Python2的内容。我用Python2面试的时候确实遇到了一次面试官吐槽的情况,不过我打个哈哈就搪塞过去了。大家能学Python3就学Python3吧。
  • 3699
305条回复