良好的开端是成功的一半。 通过使用RADIO 框架回答前端系统设计问题,您已经离面试成功更近了一步。
在前端系统设计面试中,您被要求设计的系统往往是产品,因此我们从这里开始将系统称为 "产品"。 首先了解Requirements(需求),定义高层Architecture(架构)和Data Model(数据模型)。 然后定义产品组件之间的Interfaces(接口),并讨论任何Optimizations or dive deep(优化或深入)到需要特别关注的特定领域。
目标:全面了解问题,并通过提出一些明确的问题来确定问题的范围。
建议持续时间:不超过会议时间的 15%。
系统设计面试问题的性质是开放式的,通常是模糊的,没有明确的目的。 **您需要深入挖掘问题,并通过提出有用的问题来澄清问题中的模糊之处。**将您的面试官视为与您合作开展新项目的产品经理,提出足够多的问题,以便您了解您要解决的问题以及您需要构建的内容。 实际上,有些问题根本不需要任何工程技术就可以解决!
尽管您可能会被问到相同的问题,但没有两次系统设计面试经历是相同的。 面试官的背景不同,可能会优先考虑系统的不同方面。 借此机会了解他们最感兴趣的内容,并据此计划您的回答。
在进入面试的下一环节之前,您应该回答一些一般性问题:
想象一下,您被要求 "设计 Facebook"。 Facebook 是一个庞大的平台,有信息流、个人资料、好友、群组、故事等。 您应该关注 Facebook 的哪些部分? 面试官心中已经有了答案,但希望您通过提问来找出答案。 通常情况下,您应将重点放在产品最独特的方面,即产品的特征上。 对于 Facebook 而言,这将是信息流、信息流分页和创建新帖子。 对于 YouTube 来说,这将是视频观看体验。 其他类型产品的重要区域请参见问题类型。
在本页的其余部分,我们将使用 "设计 Facebook "作为问题,并将框架应用于该问题。
假设您没有明确产品的重点,就认为应该谈论结交流程,并开始谈论它。 在最好的情况下,优秀的面试官会引导您回到问题本来的方向,但他们会在心里记下您没有澄清问题。 在最坏的情况下,没有经验的面试官会让您继续说下去,并礼貌地试图找机会纠正您,但您已经浪费了宝贵的几分钟来讨论一个不重要的话题。
首先,什么是功能性需求和非功能性需求?
您可以通过两种方式获得这个问题的答案:
最起码,您的设计必须满足功能要求。 在满足所有功能需求后,继续讨论如何满足非功能需求。
即使您知道了功能需求,仍可能有大量的小功能组成了大功能。 例如,在创建新的 Facebook 帖子时,应支持何种帖子格式? 除了常见的基于文本的帖子外,用户是否还可以上传照片、上传视频、创建投票、到某个地点签到等。
您应事先明确核心功能并进行设计,然后再进行额外功能的设计。
上述问题清单应能为您提供一个很好的问题起点,但并非详尽无遗! 不同的问题将要求您提出特定领域的问题,我们将在案例研究中讨论这些问题。
建议您将商定的要求写在某个地方,以便在整个面试过程中参考,并确保您已经涵盖了这些要求。
目标:识别产品的关键部件以及它们之间的关系。
建议持续时间:约占会议的 20%。
有了这些需求,我们就可以进行架构设计了。 您的下一项任务是通过确定产品的关键组件、这些组件之间的相互作用以及它们之间的关系,提出产品/系统架构。 切记要关注客户端架构,而不是后端。
图表是您的朋友。 每个组件都可以用一个矩形表示,您的高层设计通常最终看起来像几个矩形框,它们之间用箭头表示数据流。 也可以在组件中包含组件,在这种情况下,使用更大的矩形绘制父组件,因为它们需要适合多个子组件。
高级前端设计中常见的组件/模块示例:
定义组件责任时需要考虑的其他事项:
重要的是要认识到,并非上述每个常见组件都与每个问题相关,也并非每个问题都需要,这取决于产品。
画出架构图后,口头描述每个组件(图中方框)的职责。
下面是使用 Excalidraw 绘制的信息流问题的架构图示例。
常见的免费绘图工具包括diagrams.net和Excalidraw。 最好事先熟悉一下这些工具。
目标:描述各种数据实体、它们包含的字段以及它们属于哪个组件。
建议持续时间:约占会议时间的 10%。
现在,我们必须考虑客户端中存在哪些数据字段。 客户端应用程序有两种数据:
源自服务器的数据,通常来自数据库,可供多人查看或从多个不同设备访问。 常见的例子包括用户数据(姓名、个人头像)和用户生成的数据(动态帖子、评论)。
客户端专用数据,通常也称为状态,是只需保存在客户端而无需发送到服务器写入数据库的数据。 客户数据可进一步细分为两种:
在列出数据字段时,最好能确定该字段是哪种数据,是服务器端数据还是客户端数据。
这是一个使用信息流问题的各个实体数据模型的基本例子。
来源 | 实体 | 属于 | 字段 |
---|---|---|---|
服务端 | Post | 信息流帖子 | id , created_time , content , image , author (a User ), reactions |
服务端 | Feed | 信息流 UI | posts (Post 列表),pagination (分页元数据) |
服务端 | User | 客户端存储 | id , name , profile_photo_url |
用户输入(客户端) | NewPost | 帖子编辑器 UI | message , image |
根据你在问题中的进展以及要求在面试过程中的演变和增长,你可能需要添加更多字段。 这是一个动态和迭代的过程。
你可能想把这些字段写在你的架构图中拥有它们的组件附近。
目标:定义产品组件之间的接口、各种 API 的功能、参数和响应。
建议持续时间:约占会议时间的 15%。
有了组件和每个组件内的数据,我们就可以继续讨论组件之间的接口(API)了。 API 是一个重载的术语,通常指软件组件之间通信和请求/发送数据的协议。 客户端和服务器通过网络层 API(HTTP/WebSockets)进行通信。 客户端组件通常通过浏览器运行时的函数进行通信。 无论是在服务器和客户端之间,还是在客户端组件之间,所有的 API 都有三个共同点:
API 的组成部分 | 服务器-客户端 | 客户端-客户端 |
---|---|---|
名称和功能 | HTTP 路径 | JavaScript 函数 |
参数 | HTTP GET 查询和 POST 参数 | 函数参数 |
返回值 | HTTP 响应,一般为 JSON 格式 | 函数返回值 |
再次以信息流为例,我们有一个服务器 API,允许客户机获取最新的动态帖子。
字段 | 值 |
---|---|
HTTP 方法 | GET |
路径 | /feed |
描述 | 为用户获取信息流结果。 |
一个信息流响应是一个带有分页的列表,因此 API 预期分页参数。
{"size": 10,"cursor": "=dXNlcjpXMDdRQ1JQQTQ"}
{"pagination": {"size": 10,"next_cursor": "=dXNlcjpVMEc5V0ZYTlo"},"results": [{"id": "123","author": {"id": "456","name": "John Doe"},"content": "Hello world","image": "https://www.example.com/feed-images.jpg","reactions": {"likes": 20,"haha": 15},"created_time": 1620639583}// ... More posts.]}
客户端-客户端 API 的编写方式与服务器-客户端 API 类似,主要区别在于它们是 JavaScript 函数,或者是被监听的事件。 需要描述的最重要部分是 API 的功能、参数和返回/响应值。
如果你被要求设计一个 UI 组件,在 "界面 "部分,讨论组件的自定义选项,类似于 React 组件的道具。
目标:讨论在构建产品时可能的优化机会和感兴趣的具体领域。
建议持续时间:约占会议的 40%。
优化和深入研究部分没有固定的方法,您可以自由地关注产品的不同领域。 我们不会有足够的时间来涵盖每一个领域,因此请根据这些指导原则谨慎选择您希望花费的时间:
以下是您在本节中可以谈论的话题列表。 请注意,题目的重要性取决于问题,有些题目与某些问题完全无关(有可能,但可能性不大)。
有关每个主题的详细信息,请参阅我们的构建用户界面的最佳实践指南。
步骤 | 目标 | 推荐时长 |
---|---|---|
需求探索 | 通过提出一些明确的问题来全面了解问题并确定其范围。 | <15% |
架构/高级设计 | 识别产品的关键部件以及它们之间的关系。 | ~20% |
数据模型 | 描述各种数据实体、它们包含的字段以及它们属于哪个组件。 | ~10% |
接口定义 | 定义产品的组件之间的接口 (API),每个 API 的功能、参数和响应。 | ~15% |
优化和深入研究 | 讨论在构建产品时可能的优化机会和感兴趣的具体领域。 | ~40% |