原文: iOS「Swift|框架|模式|应用」 - 深入探讨应用架构
先进社区: 「AI PM 人工智能产品管理」
主理: Loi
架构设计是一个灵活的过程。刚开始的时候,不必着急有个最终答案,我们要有思想准备,无论是日常推进工作,还是面试中,都可能会根据新发现和结论调整内容。思考的越清晰详细,交流就越顺畅,我们的想法也能更准确地传达出来。
架构设计作为应用工程落地的前置环节,是极为关键的一步,需要我们具备更多软技能和以沟通为导向的能力。
与把握编程语言和技巧(如Swift)和精通研发框架(如Combine和Core Data)这些问题不同,在架构设计环节,需要我们更全面地考虑产品需求、后端、扩展性、分析和用户体验等因素,从而设计出一个完整的系统。
以iOS开发者为例,我们首先学习了Swift语言,并利用设计模式对其进行进一步构建。现在,我们已经来到了最高层——应用架构。
模拟「架构设计面试」
站在面试和招聘的角度,在招聘过程中,架构面试可能比其他环节更加重要,因为它基于沟通和满足期望进行评估。因此,从理解受众和面试官的角度出发,可以让架构设计的环节更具实践意义。
接下来,我们模拟一次完整的「架构设计面试」,深入思路,明确任务,开始实践应用架构的设计。
第一步 深入思路
面试官希望我们从哪里开始呢?到底期望我们做什么?
关键点是什么?
关键在于,面试官并不关心你的答案是否是最优的,或者你的答案是对是错。 架构设计面试的重点在于另一方面——面试官想要观察的是你的思考方式、解决问题的策略、如何权衡各种因素,以及你如何根据产品需求找到一个合适的解决方案。
面试问题举例:「请设计iOS系统自带的消息应用。」
显然, 消息界面(俗称「聊天」)是这个应用的核心功能 。针对这个问题,我们需要逐一应对以下几个挑战:
1. 我们将使用哪些 UI组件 ?
2. 数据模型 是怎样的?每条 消息具体有哪些属性 ?
3. 我们需要哪些 API 端点?是否需要 分页功能 ?如果不分页,如何 处理无限数量的消息 ?
4. 应用是否支持 离线使用 ?如果支持,怎么实现?
5. 应用是否支持 发送附件 ?具体如何操作?
6. 如果要加入 群聊功能 ,怎么实现?
7. 应用是否需要支持 实时更新 ?
这些问题只是面对这个任务时可能遇到的一部分,而且每个问题都相当复杂。
我们的目标就是找到这些问题的解决方案。
第二步 应对任务
很多人在面对架构设计面试时都会感到迷茫。并不是不知道如何设计一个应用,或者如何表达自己的观点,而是不知道以下两个关键点:
1. 应该从哪里开始任务?
2. 架构设计应该达到什么边界?
搞清楚这两个问题对于面试的热身和最终引导出优秀的解决方案至关重要。
我们就从任务的起点说起——理解和界定问题和范围。
1)理解问题和范围
遇到设计问题时,第一步是先停顿一下,深吸一口气,努力搞懂面试官对我们的期待。很多候选人在这一步会遇到麻烦,因为他们意识到回答问题的时间很有限,于是就急匆匆地在白板上画出框架。
但架构设计面试其实就像是现实生活中的一项任务。面试官希望我们在描述解决方案之前,能够先彻底理解问题。
比如说,假设我们要设计一个类似iOS系统自带的消息应用。我们可以向面试官提出以下几个问题:
- 我们有UI线框图吗,还是需要我们自己制作?
- 我们需要设计多少个界面?
- 设计需要包含后端服务吗?
- 这是一个跨平台应用(包括Android或Web),还是仅限iOS?
- 我们有给定的数据库方案,还是需要我们自己规划?
这些问题只是个起点,但它们能帮助我们弄清楚自己的任务。
一旦我们明白了问题本身和需要完成的任务,接下来就可以开始搜集产品需求了。
2)获取产品需求
在架构设计面试中,我们不会像处理传统开发任务那样有一份详细的产品需求文档(PRD)或与产品经理的启动会议。相反, 我们必须通过深入理解产品需求并向面试官询问更多信息来完成这个任务。 事实上,这正是面试官想要考察我们的。
想象一下,面试就像是一个漆黑的迷宫,我们手持手电筒在其中探索,逐步发现更多的区域、房间和通道。有时候,甚至面试官也不知道我们会把面试引向何方。
回到设计消息应用的任务,当我们开始设计这款应用时,可以考虑一些关键问题。以下是一些例子:
- 应用是否 支持离线阅读和写作 ?
- 是否需要 与设备的联系人功能集成 ?
- 应用是否 需要支持通知和实时聊天 ?
- 用户是否 可以编辑或删除消息 ?
- 应用是否 需要支持横屏模式 ?
这些问题并非无关紧要。它们对我们的设计和技术决策(technical decision)有着重要的影响。
例如:
- 需要 支持离线阅读和写作( 离线支持对于我们理解数据源的行为和同步机制至关重要 )
- 需要 与设备的联系人功能集成( 与设备联系人的集成会影响我们的数据模型 )
- 需要支持通知和实时聊天( 实时聊天定义了我们的网络方法 )
- 可以编辑或删除消息( 编辑和删除功能则影响了我们如何将信息同步回后端 )
一开始不必问所有问题——有时候我们需要开始设计才能明白需要问什么,但有一个良好的开端是很有帮助的。
那么,我们应该如何开始设计呢?是画线框图吗?还是定义实体?接下来,我们具体看看该如何做。
第三步 开始设计
设计环节是动态的,不是一成不变的。刚开始画图时,面试官并不期待我们就能给出最终答案。实际上,我们应该预料到,在面试过程中,随着新信息和新结论的出现,我们的设计方案可能需要进行调整。
清晰、详细地展示我们的思考过程,不仅有助于我们与面试官更好地沟通,还能表达我们的设计理念。
1)在白板上绘制线框图(wireframes)
我们不是专业的产品设计师,别人也不期望我们做到那个程度。但如何在白板上清晰地表达我们的设计思路,对于整个设计过程来说 非常关键 。「清晰的表达设计思路」,现在我们对此有了更深入的理解。
那么,我们应该从哪里开始呢?有些开发者喜欢从基本的UML图开始,描述各种实体或类。但我个人认为,在应用架构方面,从线框图开始会更合适。让我们从消息界面开始(参见图 1):
观察图5,我们可以清楚地看到,从用户界面(UI)开始设计是一个明智的选择。虽然在字体大小和布局方面我们不是专家(设计师水准),但这个线框图仍能为我们提供许多有价值的信息。
下面是一些观察实例:
- 识别不同实体 :比如,昵称和头像代表了「联系人」实体。列表显示的是联系人的最后一条消息,这涉及到文本属性,所以我们可以确定还有一个新的实体——「消息」。
- 列表按时间排序 :这可能是我们需要进一步考虑的问题——我们是希望按照每个联系人的最新消息排序,还是给联系人实体添加一个更新时间属性?这是一个典型的性能和简洁性之间的权衡;我们应该和面试官就此进行讨论。
- UI方面 ,这里应该使用UITableView。但是,我们是希望一次性将所有消息加载到表格视图中,还是支持分页加载?
- 设计模式选择 :我们需要决定采用哪种设计模式,MVC还是MVVM?我们应该根据应用规模、首屏体验和用户常见使用习惯来做出选择。
在继续之前,我要强调一点:没有绝对的答案,只有不断的权衡和思考。以上提出的这些问题,我并没有直接给出答案,因为提出问题和听面试官回答本身就是这个过程的一部分。这是我们展示自己理解并在灰区做出决策的机会。
所以,我们仅仅是用白板来绘制UI吗?不一定——让我们继续探讨。
2)添加实体与后端服务
我们已经明白一个应用远不止UI那么简单。但是,只有一个屏幕够用来开始设计应用的其他部分吗?当然足够!
让我们开始添加实体(见图2):
在白板上画出实体可能听起来挺技术范儿的,但其实,这个过程就像画线框图一样,能帮助我们挖掘应用的更多精彩细节。
比如说,我们提到了一个联系人的头像URL,这说明我们得开发一个图片下载服务,还得实现个缓存机制。所以,这个图片下载服务就可以加入到我们的白板草图中。
就凭一个实体属性的单一实体,我们就已经有了这样的成果!
但是,画实体的关键在于我们要开始考虑它们之间的关系。我们有联系人和消息实体。但是,什么决定了与联系人的对话呢?也许我们得创建一个名叫消息线程的新实体。如果我们有了消息线程实体,那它应该有哪些属性呢?
在这个阶段,事情会变得稍微复杂点,因为考虑实体之间的关联会带来更多问题——比如,我们是否支持群发消息?这个答案将决定消息线程和联系人之间的关系类型。
把实体画在线框图旁边,这个过程本身就是一个互动的过程,它帮助我们不断优化设计。每一个决策都会带来新的问题,促使我们做出更多的设计选择。这也引导我们走向下一个任务:设计应用与后端的交互。
3)添加网络调用
现在我们有了基本的UI线框图和实体,规划应用如何与后端服务交互应该会更加顺畅。记住,UI和实体还是我们应用开发初期的内容——现在我们更清楚地知道接下来要做什么。不同的端点决定了用户体验和我们将要采用的设计模式,这是我们这一章节中学到的应用架构的关键。
接下来,我们来看看主屏幕需要哪些端点(endpoints):
- GET/threads:获取所有线程列表
- POST/thread:创建新的消息线程
通常,处理信息列表时,这两个端点会作为设计的一部分。但还有其他一些问题需要考虑:
- 线程如何排序?是从服务器获取排序,还是根据特定属性排序?
- 我们需要分页机制吗?还是说我们可以一次性获取所有线程,然后用增量更新同步?
- 我们在这个阶段需要POST请求吗?还是说我们只能在发送第一条消息后才创建?
这些端点还能帮助我们定义应用架构。它们解决了关于UI层及其设计模式(如MVC/MVVM)的重要问题。同时,它们也帮助我们了解数据层和我们需要的一些不同服务。比如:
- 核心数据处理
- 图片下载器
- 同步服务
- 网络服务及实时管理
如果我们继续为其他屏幕添加更多端点,我们将会更深入地了解我们的应用,并获得更多答案。
设计应用架构是一个不断发现的过程。一开始,一切都是模糊的,沟通和寻找答案的过程非常关键。这就是为什么我们下一个话题非常关键——与面试官的沟通。
4)与面试官的有效沟通
很多面试者错误地认为,在架构设计面试中,他们的主要目标是给出他们刚刚想到的最优化解决方案。但实际上,面试官希望通过这个过程看到我们如何思考,并提供一个对可能出现的问题来说合理的解决方案。
因此,在这种面试中与面试官的有效沟通至关重要。我们的一些最关键的软技能正是在这里得到考验的!
下面是一些帮助我们关注 重点的建议:
- 真正倾听面试官 :这听起来很简单,对吧?当然我们会听面试官的话!但我的意思是,要真正地倾听他们。首先,任务要求和范围对于精确确定我们做什么非常重要。此外,面试官会给我们一些有价值的提示,帮助我们实现目标。
- 如果你对自己的决定不确定,要向面试官澄清疑虑 。面试官需要看到我们能看到事情的灰色地带,而不仅仅是黑白分明,这也是获得线索或与面试官讨论事情的方式。
- 保持自信 :我知道这听起来似乎与前面的点相矛盾,但它其实并不矛盾。当我们有疑虑时,我们需要向面试官沟通,但当我们对自己有信心时,我们必须展示出来。自信是这些面试中的一个关键因素。
- 大声思考 :我们知道我们想要通过设计实现什么,甚至已经在白板上画出来了。但对我们来说显而易见的事情,对房间里的另一个人来说不一定明显。大声思考可以帮助我们更清楚地解释我们在做什么,并帮助面试官理解我们刚刚设计出的出色架构。
- 使用正确的术语 :在这本书中,我对使用的不同术语非常严格——方法与函数、设计模式与架构等。在这些面试中使用正确的术语至关重要,这不仅仅是为了显得专业;它还使我们的解释更容易让面试官理解。并非所有面试官都对这一点严格——但这并不意味着我们不应该这样做。
- 接受反馈 :在面试过程中,面试官可能会提供反馈或建议。有时这是一个我们可以采取方向的线索,有时是因为我们超出了范围。很多情况下,在这种情况下,候选人会失去自信,封闭自己,难以接受反馈。我们应该在设计面试中抛开自己的 ego(自负),并利用面试官的反馈来改进我们的答案。面试过程中的反馈并不意味着我们失败——它意味着我们有机会提供更好的解决方案。
看起来我们正在接受如何沟通和表达自己的考验,但这就是现实!面试官想看到我们在一起工作、讨论设计问题、进行架构辩论的样子。这就是我们的个性闪耀的时候。
总结
架构设计面试是招聘过程中最为关键的一环。它综合了设计模式、架构设计、iOS用户体验,以及规划、沟通和展示等关键的软技能。
到此,我们应该已经掌握了一些关键步骤,能够自信地面对面试。我们研究了SoC原则及其在iOS架构中的应用,包括函数的大小和命名。我们探讨了应用的层次结构以及数据流动,甚至还举了一个优秀的离线工作架构示例。最后,我们讨论了架构设计面试的策略——如何应对以及如何与面试官沟通。
架构设计是一个灵活的过程。在架构设计环节,需要我们更全面地考虑产品需求、后端、扩展性、分析和用户体验等因素,从而设计出一个完整的系统。
参考:
【 The Ultimate iOS Interview Playbook】by Avi Tsadok,Released August 2023 Publisher(s): Packt Publishing, ISBN: 9781803246314
主文档 iOS「Swift|框架|模式|应用」
参考:【The Ultimate iOS Interview Playbook】
备注:参考材料供本人学习所用,译成中文供团队内部学习。如果对全世界的你们也有帮助,深感荣幸。
先进社区: 「AI PM 人工智能产品管理」
主理:Loi