我在之前的文章中讲述了硅谷如何培训优秀的编程面试官。这篇文章的侧重点是系统设计面试。通过阅读本文,希望读者对硅谷培训程序员系统面试官的方式有更多的了解。
硅谷大部分公司(FB、 Amazon、 Uber 等)会有专门的一场面试考察候选人的系统设计能力。一些公司(如 Google)会时常把系统面试和编程面试或者行为面试混在一起考察。无论是哪种形式,过硬的系统设计能力都是优秀程序员必备的能力,所以系统设计则是面试中的必不可少的一个环节。候选人等级越高,对候选人的系统设计能力要求也就越高。根据候选人的等级(初级,中级,高级,staff 等)和岗位(比如产品,infra 等),面试官需要对系统设计题目的内容和难度做出一定的调整,在下面的文章中会做出详细说明。本文不会涉及具体某个系统,而是把重点放在面试方法上。因为技术更新的很快,而面试题目也会因为被用的次数太多而被抛弃,但是面试的方法和思路是很少改变的。
所有的问题解决方案都应该从问题本身出发
开发系统就是为了解决问题。那么在设计系统之前就要分析问题的本身。我发现越是有经验的候选人,越是会在开始设计前弄清楚要解决的问题是什么。比如:“我们为什么要设计这个系统?”, ”我们具体要解决什么问题?“。这就好比一个人管你要锤子,帮助这个人的最优的方式不是给他一个锤子,也不是问他要什么样的锤子,而是问清他到底要做什么?如果这个人的目的是开核桃,给他一个核桃夹子更能帮助到他。有些候选人会认为问题的本身不言而喻。然而在现实中,开发的系统不解决用户问题的例子比比皆是。我们在面试中要寻找那些会从用户角度出发思考问题的人。
除此之外,候选人应当主动去了解问题的细节。比如 DAU 是多少?具体要提供哪些功能?系统需要支持什么操作?是不是大部分情况下是读操作?这些细节问题会直接影响整个系统的设计。这个环节面试官可以让候选人自己提出假设。重点不是什么假设,而是假设是否合理。面试官在一开始描述问题时,可以选择模糊细节以鼓励候选人提问。比如问题可以是:设计谷歌地图、设计 Redis。这些系统和产品不可能在短时间内设计出来,因此面试者必须首先确定问题的范围。
定义成功
另外一个候选人经常忽略的问题是如何定义系统的成功?根据要设计系统的不同,成功的衡量标准可以是具体的数字指标:比如延时在 200 毫秒以内,吞吐率在 1k/s 等。也可以是功能的实现:比如最终一致或者提供搜索功能。或者是定义成功的指标:比如 DAU、MAU,留存率等。有经验的候选人一般会很自然的提出这点,因为在日常的工作中,定义成功是系统设计中十分重要的一个环节。这个部分答案本身并不重要,重要的是为什么是这个答案。比如候选人定的目标是延时在 200 毫秒以内,重要的是候选人能否说清楚为什么要在 200 毫秒以内,而不是 500 毫秒或者 1 秒。
系统组件设计
候选人应该具有从全局出发的能力,思考系统需要什么组件,每一个组件的职责是什么。常见的错误包括:
组件的职责不清楚:候选人无法解释清楚一个组件到底是做什么的。
一个组件负责的功能太多:候选人应当拆分组件以增加可复用性。
功能放在了错误的组件上。
组件高度耦合:一个组件过于依赖另外一个组件的具体实现。产品工程师可以把重点放在组件API的设计上。
估算
容量估算是系统设计中重要的一个环节。候选人需要根据之前所给的需求量、数据量等指标来预测设计是否可行以及需要消耗多少资源。如果候选人没有预估,面试官应该主动要求候选人做出计算。比如:我们需要部署多少台机器?每天需要新增多少存储?给出的答案不重要,重要的是候选人的预估是否合理。如果做出了假设,假设是否合理?预估很有可能会影响系统设计中所做出的选择,所以要及时讨论可能存在的问题。有经验的候选人会时常停下来做预估。
提出多种方案,利弊权衡,做出选择
面试官应当鼓励候选人给出不同的解决方案,并询问每种方案的优缺点。候选人应当最终选择一种方案,然后给出选择的理由。面试过程中偶尔会遇到优柔寡断的候选人,面试官应该鼓励候选人做出最终决定。因为不选择很多时候比做错误的选择代价还要高。
挖掘 T 型人才
T 型人才是指一个人的知识点既有深度又有广度。他对全栈的每一个部分都有一定的了解,但是又对某一个或几个领域有很深的研究。T 型人才的深度可以帮助公司解决复杂的问题。而他们的广度可以让他们更好的和他人合作。想找到 T 型人才就需要在面试过程中深度探讨一些技术细节。建议面试官提前阅读面试者的简历,并找到面试者所熟知的领域。比如数据库、网络、系统安全等,在面试的过程中可以花多一点时间讨论这些领域,深挖细节。所选的领域最好是面试者熟悉的,否则很难对候选人做出正确的评估。但是注意避免因讨论过多的细节而没能给面试者足够的时间设计出端到端的解决方案。
把握面试的节奏
如果面试是一个小时的话,我一般这么分割时间:
0-5分钟:问面试者是不是需要喝水上卫生间。简单的互相介绍一下,问问面试者之前的经历。从面试者熟悉的内容开始有助于缓解面试者紧张的情绪。
5-55分钟:做题。这个时候你需要尽量收集面试者的信息。所以如果面试者卡在某个具体的问题上太久,你可以适当地给一些提示,如果在一个问题上花费太多的时间,他就没有机会把系统设计完整了。
55-60分钟:回答面试者的问题。这个环节有两个事情需要做:第一是推销你的公司,第二是从其他方面了解面试者。面试者的问题很多时候都反映出了工作中哪些地方对他/她重要。比如公司文化,工作时长等。
如果面试是 45 分钟,我会把中间做题的时间缩短,前后的十分钟保持不变。因为两部分对面试十分重要,不能缩的更短了。
根据候选人的等级和岗位调整题目
一般本科毕业生(对应 Google level 3)并不具备很强的复杂系统设计能力。上学阶段很少有机会设计大型系统,所以 OOP 设计比较合适初级工程师。对与中级工程师(level 4)的要求是可以做小型项目,所以可以问 service oriented 架构设计。高级工程师(level 5)则需要涉及到到可扩展性、高可用、跨数据中心等问题。Staff engineer (level 6) 在 level 5 的基础上还要从多方面考虑系统的 operations。比如可测试性,安全性和可调试性等。对于系统中每个组成部分都要有比高级工程师更深刻的理解。
对于不同的岗位,系统面试的侧重点也应该不同。比如前端工程师的系统面试形式和后端就不太一样。做 infra 的和做产品的也不一样。做 ML 的和大家都不一样。大部分公司做产品的工程师不需要知道公司下半年要多买多少台机器来支撑服务,而 infra 的题目不需要有太多的 API 设计。产品工程师要考虑用户的交互,而这些并不是 infra 面试的重点。在选择面试题目和难度的时候都要根据工程师的级别和岗位做出相应的调整。否则既无法做出正确的判断,候选人的面试体验也很差。
建立系统设计面官试培训流程
系统设计面试的难点在于问题通常没有统一的答案和标准。根据候选人申请的岗位、级别、背景不同,面试官要对题目进行调整。因此设立面试培训流程就很有帮助。流程一般包括三步:培训,实例分析和面试观摩。培训的内容可以以本文做参考。实例分析中,经验丰富的面试官找一到两道真题,掰开揉碎讲给学习者听,通过例子告诉学习者哪里是考点、哪里是难点、如何给提示、如何评级等。面试观摩一般分为两步:观摩和反向观摩。观摩一般是去旁听有经验的面试官面试。反向观摩则是有经验的面试官去旁听学习者的面试,提出改进意见并且打分。不合格的需要反复进行这个部分。对于新的题目,在拿来面试之前,一定要找同事来模拟,以保证题目的质量和评判标准的准确性。
写在最后
和其它形式的面试一样,面试官培训中要包含其它的一些主题,比如如何写好面试反馈,如何决定是不是发 offer,面试官在面试过程中要注意什么等。这些内容可以在之前的文章中找到,这里就不赘述了。
俗话说:文无第一,武无第二。如果说编程题目是比武的话,系统设计就是比文了。系统设计没有正确的答案,只有适合不适合。面试官不应心存完美的设计,并要求面试者给出一模一样的答案。对于同一道题目,每个候选人都会给出不一样的设计。我们要分析每一个设计的利弊。
评论 4 条评论