搞定系统设计 03:系统设计面试的答题框架
终于要讲到答题框架了!
我们说系统设计面试题没有统一的答案,但答题过程还是有一定的规律可寻,这就是第 3 章要讲到的答题框架。
系统设计面试中,经常会被问到如何设计微信、如何设计微博、如何设计百度……我们怎么能在如此短的时间内设计出来一个由成千上万的码农、PM,经年累月地迭代出来的如此优秀的产品?如果面试者这么优秀,那还面试啥?百度、谷歌也不可能只是一个搜索框而已,底下的东西复杂去了。
所以,这种问题的答案一定不可能是全面的,面试官也不会期望我们给出一个满分答案,这点是要首先明确的。
所谓的系统设计面试实际上是在模拟一个场景:两名同事在一起就一个模糊的问题,讨论一番,得出一个还不错的解决方案。
问题是开放性的,没有标准答案。并且最终的设计是怎么样并没有求职者在整个过程中表现出来的能力、思维方式重要。过程中,我们需要“一惊一乍”,需要回答面试官的问题、回应他的质疑、证明我们的选择。
面试官的目标是充分挖掘求职者的能力,并在面试结束时给出过或不过的结论。
那么面试官到底想在一场系统设计的面试中得到关于求职者的什么信息呢?
很多人认为系统设计面试就是考察求职者的技术设计能力。但真实情况要考虑得更多:合作能力、抗压能力、问出高水平问题的能力……甚至有一些面试官非常看重问问题的能力。
另一方面,面试官也在寻找一些“不好的品质”,例如过度设计。求职者倾向于设计出一些完美、不做取舍,不控制成本的方案。这样的人招进来后,最终需要公司买单。其他“不好的品质”还包括:思路狭窄、固执、沟通能力差……这些都是要尽量避免表现出来的。
四步法
虽然系统设计面试是开放性的,且没有“一招吃遍天下”的招式,但一次成功的面试还是会遵循一些步骤:4 步法。
第一步:理解问题,设定边界
当面试官给出问题时,不要马上给出答案。系统设计面试没有标准答案,脱口而出说明求职者并没有考虑清楚。当没有彻底理解面试官意图的情况下就给一个答案通常会给面试官释放一个不好的信号:我很浮躁。
要想厘清问题,弄清面试官真实的意图是什么,就必须要和面试官你来我往地问问题。第一步就是要确定要求和假设。
对于求职者,在弄清问题后,不要马上就给出一个最终的设计版本,因为这通常会是一个错误的版本。始终要记住:最终的设计是什么样并没有那么重要,重要的信息已经整个面试过程中传递给了面试官。
所以正确的做法是:在做设计的同时,问面试官的要求是什么,做出合理的假设、取舍,让面试官看出你的思考过程,最终综合所有的信息完成一个还不错的设计。
不要害怕问问题。那并不会说明我们不懂,而是让面试官理解我们的思考过程。
当我们问出问题后,面试官要么给出明确的回答;要么让我们自己做出假设。当需要做出假设时,我们需要把假设写下来备用。
那我们应该问出什么样的问题呢?这有一些典型的例子:
这个系统的核心功能是什么? 有多少用户使用我们的产品? 公司的业务发展速度怎么样,3 个月、半年、一年后,规模会变成多大? 公司的技术栈是什么?有什么现存的服务可以简化我们的设计。
第二步:提出整体设计,达成一致
这一步,目标是画出一个高层次的整体设计,过程中和面试官合作,并和面试官达成一致。
想出一个最初版本的设计。询问面试官是否可行。要把面试官当成一起工作的同事,这就是一个平常的讨论。 在纸上用线框图画出关键的组件。包括:客户端、API、服务端、数据库、缓存、CDN、消息队列…… 做一个估算,看第一版的设计是否满足当前的用户规模。当然,是否要做估算可以先和面试官交流。
如果可能的话,设想几个具体的例子,对着图演练一遍。这让我们能更坚定当前的设计,有时候还能发现一些未考虑到的边界 case。
有个问题是:我们需要设计 API 和数据库的 schema 吗?这个取关于面试题是什么,如果面试官让我们设计一个谷歌搜索引擎,那显然是不需要的,这个问题层次太低了。但如果问题是设计一个多人扑克游戏的后端,可能这就是考点了。当然,这些都可以向面试官求证,由他决定。
第三步:深入设计
到达这一步时,我们和面试官应该已经达成了如下的一致:
总体目标和要完成的功能 一个整体设计图 从面试官那里获得了关于这个设计的反馈 通过反馈,知道了接下来要对哪些方面做深入细致的设计
我们要和面试官确定接下来应该聚焦到哪些组件,这在不同面试场景中不会相同。即使是相同的题目,不同的面试官想考察的点也可能不一样。有些面试官就喜欢讨论顶层设计,画 PPT 好看😀;有时在一个高级职位的面试中,面试官更想讨论系统的性能,讨论瓶颈和资源预估。大部分时候,面试官还是会想就某个或一些组件进行深入地探讨。例如,对于一个短网址应用,重点讨论哈希转换算法;对于一个聊天系统,面试官更关注如何减少系统延迟以及如何支持在线、离线状态。
面试中的时间管理也是有学问的。不要在没有用、不能有效证明你能力的细节上浪费太多时间。例如在设计一个可伸缩的系统时,大谈 PageRank 算法,这对面试结果没有什么帮助。
第四步:杀青
这是最后一步,面试官会问一些后续的问题、讨论一些其他的点,这有几点建议的方向:
面试官想要我们识别出当前设计的瓶颈并且给出改进。所以,永远不要说我们的设计是完美的且没有改进的余地。每个系统都能做出优化。这里实际上可以展现我们的批判性思维,指出现有设计的问题、如何改进,给面试官最后留下一个完美的印象。 帮助面试官回顾一下我们在整个过程中所做的各种设计。如果我们在面试过程中提出了多种方案的话,这可以避免面试官遗忘。 故障处理。例如服务器挂了、网络中断了等等故障,都是很好的话题。 运维。如何监控各种指标、错误日志,如何回滚。 如何应对更大的规模。例如我们当前的设计能够支撑 100w 用户,那么当用户数达到 1000w 时,需要如何应对。 提出一些其他组件的精细设计。
关于要做的和不要做的列表
要做的:
如果要做出假设,向面试官确认是否可行。 理解问题的要求是什么。 没有最好的答案,也没有正确的答案。不同方案适合不同的场景:对于创业公司来说,怎么方便、快速怎么来;而对于有着百万用户的公司来说,可用性、稳定性才是更重要的。所以,要事先确认面试官到底想要哪种。 让面试官知道你在想什么。不要闷头不说话,因为很可能我们在一个错误的路径上思考半天,浪费了时间。 如果可能的话,提出多种方案。 一旦和面试官在整体框图上达成一致,接下来就要细化设计单个组件,记得先从最重要的组件开始。 从面试官那里获得一些点子。好的面试官在此刻就是一位同事。 永不言弃。
不要做的:
不提前准备典型面试题。 不要直接提出一个解决方案而不弄清要求和假设。 不要一开始就给单一的组件做非常详细的设计。先给总体设计再往下深入。 如果卡住了,不要闷着,大胆向面试官寻求提示。 再次强调:不要闷头思考。 不要想着当我们给出了设计方案的时候,面试就结束了。只有当面试官说结束的时候才是结束的时候,面试过程中,要经常问面试官:这样设计怎么样,有问题吗?
每一步的时间如何分配
总体而言,系统设计面试可以问的问题是非常宽泛和灵活的,45 分钟到 1 个小时不可能覆盖整个设计,所以时间分配是很重要的。
那我们应该在每一步各花多少时间呢?其实并没有一个标准的答案,还是那句话:取决于面试官和面试题目。归根结底,要看面试官如何安排,看他想考察求职者哪方面的能力。
这里给出一个大概的参考:
步骤 | 时长 |
---|---|
第一步:理解问题,设定边界 | 3-10' |
第二步:提出整体设计,达成一致 | 10-15' |
第三步:深入设计 | 10-25' |
第四步:杀青 | 3-5' |