拥有良好的系统设计能力,是一个优秀程序员的必要素质。
当然更重要的是,越来越多的公司在面试中考察系统设计能力,尤其是外企巨头,如谷歌,亚马逊,微软等。这些公司对于社招的软件工程师往往有这方面的要求。
但是系统设计和算法题不一样,它考察的是程序员对于复杂系统的理解与设计,更重要的是沟通与思维。
还有一点不一样的是,每一个系统设计问题都没有明确唯一的答案,目前也没有直接的教材。不过,令人高兴的是,国外目前有一本关于系统设计的书,详细讲解了系统设计涉及到的方方面面,它用几个实际例子引导读者一步步了解并熟悉系统设计, 以求让读者在实际工作中进行系统设计时有更完善的考虑,并且在未来可能的面试中能从容应对系统设计相关考核。
我在这本书的前几页就读到了其精髓,在此与大家分享。
--------------------------------------------------------------
系统设计过程中的几大步骤:
- 需求澄清(Requirments Clarification)
- 系统接口定义 (System Interface Definition)
- 粗略估算 (Back-of-the-envelope Estimation )
- 定义数据模型 (Defining Data Model)
- 高级定义 (High Level Design)
- 细节设计(Detailed Design)
- 识别并解决瓶颈(Indentitying and Resovling Bottlenecks)
---------------------------------------------------------------
每一个步骤都介绍了我们具体需要做的事情,下面再稍微详细地介绍。
需求澄清可以说是最重要的一步。在我们进行系统设计前,我们必须清楚地明白,要解决的问题是什么?系统设计问题往往是开放性问题,它没有唯一的答案,对于求职者来说,在需求澄清这一步的表现对面试的结果是关键的。对于一场关于系统设计的面试来说,往往只有40分钟左右。因此我们必须明确,要关注的重点在哪里?
举一个实际的例子,假设要求设计一个类似推特的系统。在进行下一步之前,我们需要问出以下问题:
诸如此类的问题,将帮助我们定义出一个合适的系统。
这个过程,我们需要定义这个系统用得着的API。这些API可以精确体现出我们希望这个系统能做什么,确保我们在设计时对需求的理解没有出现错误。
还是用这个推特系统来举例。 一些可能的API如下:
postTweet(user_id, tweet_data, user_location, tweet_location, timeline, …);
generateTimeline(user_id, current_time, …);
followPeople(user_id, followee_id, …);
markFavorateTweet(user_id, tweet_id, timeStamp, …);
在我们即将设计系统时,一个很好的做法是,先估算一下它的规模。这将有助于我们之后关注scaling, partitioning, load balancing & caching.
尽早定义数据模型可以理顺系统中的数据是如何在各个模块中流动的。这会指导之后的数据分区和管理设计。面试者应该能识别设计出系统所需要的各个实体,以及它们之间应该怎么互动,还有诸如数据管理(存储,分区,加密)等方面的内容。
以这个类似推特的系统举例:
User: UserID, Name, Email, DoB, CreationData, LastLogin, ect.
Tweet: TweetID, Content, TweetLocation, NumberOfLikes, TimeStamp, ect.
UserFollowo: UserID1, UserID2
FavoriteTweet: UserID, TweetID, TimeStamp
基于数据模型,我们应该选择合适的数据系统。该用NOSQL还是MYSQL呢?为了存储图片和视频,我们应该选择什么块存储方式呢?
画出系统核心模块的类图。我们需要识别出端到端的各个模块。
对于推特来说,我们需要不同的应用服务来完成读/写请求和负载均衡等。如果我们能假设将有更多的读拥堵(相较于写),我们就可以决定在不同的场景中使用不同的服务器。我们需要高效的数据库来存储所有的推特和支持超大量的读要求,还需要一个分布式存储系统来保存图像和视频。
深入挖掘两到三个模块,由面试官的反馈来引导我们来决定哪些个模块需要更多更深入的讨论。我们应该有能力提出不同的方案,并且罗列它们的优势和劣势,并解释为什么我们选择其中的某一种,而不是另一种。
记住,这里没有唯一的答案。重要的是,在系统现有限制的情况下,对不同的方案进行tradeoff选择。
你需要对以下问题有所考虑:
尽可能多地找到瓶颈(存在的或者潜在的),以及尽可能多地提出解决方案。
简单总结一下, 做好准备和有条理,这两点是成功完成系统设计面试的关键。在进行系统设计时,以上几个步骤基本覆盖了所有涉及的方面。那么之后再遇到系统设计时,我们可以沿着这个指导步骤来入手,进行具体的设计。