移动客户端架构案例分析与思考

移动客户端架构案例分析与思考

写在前面

关于题目

分享以前,想说一下为何选择了“架构”这个主题,其实初衷有两个:html

第一,“架构”对于咱们来讲实在是过重要了,我们虽然没有架构师这个职位,可是在开发的时候,都须要先有个很好的设计,但愿咱们的代码是易维护的,而“设计”每每都会落到“架构”上。因此但愿此次分享可以对于你们在架构设计上有一点帮助。react

第二,即使“架构”如此的重要,你们再聊到“架构”这个话题的时候,仍是感受到有点“虚”。想一想缘由,多是由于每一个人对于“架构”的理解可能都不太同样,一我的在不一样阶段对于“架构”的理解也会不同,架构设计还很依赖于实践和经验,不少设计细节(取舍)都是在实践中不停的迭代、改进,进而反思才能获得价值观的升级。因此我借此次机会,也将我本身以前零散的架构方面的理解,总结一下,争取能造成一点体系上的认识。但愿你们聊起架构时,能稍微不那么“虚”。ios

分享形式

为了避免那么枯燥,今天分享形式,我选了3个架构的案例,来进行分析,来试图讲清楚我对于架构的认识,以及怎么样设计出一个好的架构,固然这个话题太大了,我今天先给你们开个头,但愿先能有一点感受就好。面试

最后但愿你们带着批判的精神来听,欢迎多交流。算法

第一个案例:猎户语音iOS SDK —— 架构是被业务驱动的

第一个案例,举一个咱们本身的,放在第一个来说,也是想强调“懂业务”对于设计出好的架构来讲,是很是重要的,这也是一些人每每会忽略的点。数据库

不少同窗确定想,在项目的一开始,就设计一个完美的架构,之后能 hold 住各类变化。其实这是不可能的,架构必定是随着业务的变化,而不停的演化和进化的,在有的阶段还可能对于以前架构作比较大的调整。react-native

背景

你们都知道,咱们同时维护了几个App,好比小豹、小雅、锤子等,这些上层App,都要依赖于底层的一些framework,好比设计模式

  • 业务中心 OrionServiceSDK.framework (包括不少主要业务)
  • 信息流 OVSChat.framework
  • 技能商店 OVSSkillStore.framework
  • 声纹 OVSVoicePrint.framework
  • 等等

在早些的时候,咱们对于 SDK 的拆分粒度比较细,好比一个“找手机”技能,都会作成一个 framework。当时的 framework,应该在20个左右,各个 framework(组件) 的依赖关系图以下:服务器

历史缘由

咱们这么作当时的缘由很简单,但愿可以解耦各个组件,将组件尽可能拆细,而后App方想使用什么功能均可以作到热插拔,很少也很多,多好~网络

理想 VS 现实

理想和现实每每会出现矛盾,到实际应用的时候,这样的设计就给咱们带来了问题。若是对每一个 framework 进行编号,好比1到20,那么咱们理想中是这样的:

可是现实实际上是这样的:

对比两张图的含义就是,实现中咱们各个App,使用的 framework 大致相同,咱们即使把业务拆的很细,若干个被拆分的 framework 其实还老是绑在一块儿使用。而且,还给咱们维护带来了巨大的问题,光每次打Git tag,都要折腾一会,会感受精力都花在了一块儿辅助工做上。

优化

针对这个问题,咱们专门优化了 framework 的个数,将类似业务的 framework 进行了合并,最终 framework 的数量减小到了10个一下,组件之间的依赖图变成这样:

优化以后效果也很明显,咱们对于各个framework的维护,变得简单多了。

两个彩蛋

另外在优化的过程,有两个值得一提的是:

  1. 以前“信息流“和”推送“还存在环状依赖的问题,就会致使当你想把 ”推送“的framework合并到业务中心的时候,居然还得让业务中心去依赖信息流,这个固然是没法忍受的,解决办法也比较经典,就是让依赖下沉,把 Push 依赖的信息流的协议,放到了业务中心中。
  2. 此次的优化,实际上是将”松散“变成了”耦合“,和咱们平时常提到的观点恰好相反,可是确实是咱们当前甚至从此一段时间内作因此我想说的是,”耦合“其实只是一个特征,虽然大部分状况是缺陷的特征,可是当耦合成为需求的时候,耦合就不是缺陷了。(有没有一点在哪里听过的感受)

小结

咱们谈”架构“的时候,说的最多的就是”取舍“,什么叫”取舍“,就是说你不能很简单的就判别出哪一个是好的,哪一个是很差的,老是以为有点左右为难。而如何取舍?业务就是很是重要的一个标杆,只有结合业务,才能判断出哪一个是最适合本身的。咱们结合了业务,对本身的 framework 的数量进行了精简,固然也可能会根据业务的变化,在将来某天,须要将现有的framework拆分的更细。

第二个案例:饿了么移动APP的架构演进 —— 造成体系的认识

你作的项目,技术架构是怎么样的?

几乎全部人在被面试或者面试别人的的时候,都会(被)问到这个问题,不少人会回答,咱们架构是MVC(MVVM),少数人还会使用MVP或者VIPER,咱们姑且都称为MV(X),可是真的架构仅仅就是MV(X)吗?其实我以为MV(X)虽然是架构中比较重要的部分,可是仍是远远不能说架构 = MV(X)。

为何呢?带着这个问题,咱们来看第二个例子,在这个案例中,咱们关注下面几点:

  1. 架构是如何随着业务的变化而变化的(这个也是对上面观点的一个证明)。
  2. 咱们谈到架构就提的 MV(X),处于架构中的哪一个部分。
  3. 经过”饿了么“的架构演变,体会一下每一个阶段的侧重点是什么,对于架构有一个体系上的认识。

文章地址:

饿了么移动APP的架构演进
https://www.jianshu.com/p/2141fb0dc62c

”饿了么“的架构经历了4个阶段的演化:

  1. 第一阶段 MVC
  2. 第二阶段 Module Decoupled (组件化)
  3. 第三阶段 Hybrid
  4. 第四阶段 React-Native & Hot Patch

第一阶段 MVC

这个古老而经典的模式,不用多说。它是一个软件”从无到有“,”短平快“开发的首选。也是大部分规模比较小的 App 几乎大部分时间精力都会与之打交道的一个架构,以致于人们提架构比弹MVC。

固然这个架构随着业务的剧增,很快就会出现弊端,朝着Massive-View-Controller的方向奔去。

第二阶段 Module Decoupled

随着代码量不断增长,功能模块愈来愈多,无论是分工开发协做,仍是已有模块的复用和维护,组件化都成了这个阶段的重点。组件化有个两个关键:

  1. 如何划分组件。
  2. 如何实现组件之间的通讯。

对于第一个问题,”饿了么“采用的方案,基本是业界广为使用的分类方案,将组件分为共有组件和业务组件,

  • 公共组件提供了一些业务无关的基础服务:好比网络库、数据库、JSONModel等
  • 业务组件则对应具体的一块业务,好比登陆业务组件,订单组件等

对于两种组件的管理:

  • 对于公共组件,使用CocoaPods进行版本管理(这点和咱们目前不太同样,由于咱们是SDK提供方,咱们引用的第三方库,不肯定咱们的SDK使用方是否使用,是否更改源码,因此咱们的方式,是将稳定版本的源码,混淆后打包进咱们的代码)。
  • 对于业务组件,这个和咱们大致相似,采起了业务模块注册机制的方式来达到解耦的目的,每一个业务模块对外提供相应的业务接口,再启动时向一个中心注册本身的Scheme(咱们是协议)。

而在具体某个业务组件内部,则能够根据不一样开发人员,不一样队伍的偏好,来实现不一样的代码架构,好比MVC、MVVM、MVP等,也都不会影响总体系统架构。

这时的架构图,看上去长这样:

咱们能够看到,MV(X) 已经不是关注的所有了,不少模块已经和 MV(X) 不怎么搭边了。

因此说,架构不等于 MV(X),其实 MV(X) 关注的只是”应用层“的部分

关于分层:
通常的,能够将App分为三层:应用层、service层、data access层。

  • 应用层 是直接和用户打交道的部分,咱们经常使用到的 UIViewController,Android的 Activity,负责了数据的展现、流向、用户交互的处理。
  • service 层 是在应用层的下面,为应用层服务器的,对于应用层来讲就像一个API调用延迟为0ms的Server API。通常会放在应用层的代码:网络接口调用、公共系统服务API(GPS定位、隐私权限访问)、一些 UTil 代码(因此我以为好比一个 UIViewController 的一些私有方法和一些提工具性质的category,其实应该算serveice 层)。
  • data access 提供和对于数据的”增删改查“的接口层。

第三阶段 Hybrid

业务的变化又来啦,当用户规模达到比较大的数量,此次不只仅是功能的增长,每两周一版已经知足不了产品、运营躁动的心了;同时,用纯 Native 代码编写的 App,若是上线后有错误,只能等下一次提交市场。在现在互联网竞争如此激烈的时代,一次线上错误有时也会带来很大的影响。因此这时候,不少纯粹展现性的模块会使用 H5 的方式来实现。

可是这种方式也有它的弊端:

  • 每次加载页面须要请求服务器,渲染时间比较长。
  • 调用本地硬件设备存在必定的不便。

对于这个问题,也有不少方案能够权衡,好比能够提早将网页打包好,以减小网络传输的时间,同时提供一系列的插件来访问本地的硬件设备。

“饿了么”这里的作法是,综合了 Native 和 H5 的优缺点,将页面作了一个划分,纯粹展现性的模块使用 H5;而更多的数据操做、动画渲染性的模块使用 Native。

架构图长成这样子:

业务再一次再架构的演化中扮演了重要的角色。

第四阶段 React-Native & Hot Patch

又要频繁迭代,又要用户体验,这时就考虑到了RN;另外,饿了么这个阶段用户已通过亿,线上一个小 bug 均可能影响几万人的使用,因此这个阶段,重点在于 RN 模块的引入,以及 Hot Patch 热修复功能的引入。

在 RN 的使用方面,依然有一个取舍,要回答下面的问题:

  • 哪些页面使用 RN,哪些页面不用 RN。
  • 是整个模块使用 RN,仍是一个模块的部分页面使用 RN。
  • RN 和 Native 页面是2选1的关系,仍是说是一个备份。
  • RN 和 Native 页面如何通讯。

“饿了么”的作法是:对于20%最重要的页面,作了一个 RN 的镜像,也就是一个备份,而后经过服务器的配置,来切换Native 仍是 RN,这样若是 Native 页面出现问题的时候,先经过开关将线上的页面切换成 RN,先保证线上正常使用,而后使用 Hot Patch 完成修补后,再切换回 Native App 原生页面。

这时的架构图:

不得不说,这种作法不必定适合别的团队,毕竟一个页面,要写 Native 、 RN 两套代码,而且要一直维护,花的代价都有点大,不是每一个团队都有精力去这么搞的。其实这点,也正说明了,你须要根据本身业务,设计出一个最适合本身项目的架构。

小结

小结一下:

  1. 业务一直在影响架构的变迁。
  2. MV(X) 其实只是“应用层”的事,对于架构应该有个系统的认识。
  3. 架构的设计,并非有现成的拿来用就 OK 的事,还有不少细节的部分须要作取舍,依赖业务需求和经验。

第三个案例:《猿题库 iOS 客户端架构设计》—— 好的架构具备哪些特质

第三个案例咱们回归 MV(X),毕竟它确实是咱们平常开发接触比较多的一部分。

对了这个案例,想关注的“点”是

  1. MVC 和 MVVM 的优缺点。
  2. 如何可以规避缺点,结合优势,改进架构,设计一个适合本身的MV(X)架构。
  3. 这个思想的底层原理是什么,在别的场景下的设计可以通用。

文章地址:

猿题库 iOS 客户端架构设计
http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/

MVC

优势:

  1. 易理解,对应现实生活中也是这样的。
  2. 易上手,iOS、Android 默认就是个 MVC 的环境。

缺点:

  1. 当指责不是那么明确,不知道该放哪时,代码就会被放在"Controller"里面吧,Controller愈来愈难维护。

其实对于上面这个缺点,唐巧也在一篇文章中写道,这个问题其实也不能说是 MVC 的缺点,是咱们没有拆分好代码。能够看看唐巧的《被误解的 MVC 和被神化的 MVVM》,提出了一些如何解决 Controler 臃肿的解决办法,而后也表达了对于 MVVM 的质疑,具体的作法能够去读这篇文章。这也正说明了你们对于架构的理解和态度真的是有区别的。

MVVM

具体关于MVVM的概念能够参考 Objc 的《MVVM 介绍》,这里就不具体说 MVVM 的概念了。

不了解MVVM的同窗,知道这几点就行:

  1. MVVM将ViewController视做View。
  2. 关于 View Model,只须要知道两件事:持有model;View能够彻底经过一个View Model决定本身如何展现。
  3. View 和 View Model,View Model 和 Model之间经过数据绑定,使得 Model改变的时候,能同步更新 View Model,进而更新 View。

优势:

  1. 减轻了 Controller 的负担,拆分了代码
  2. View Model有比较好的测试性。
  3. 结合 RAC, 能够将数据和 View 通讯的代码精简到不多。

缺点:

  1. 上手成本高。
  2. 因为使用数据绑定,界面的 bug 变的不易调试。
  3. ViewModel 接管了 ViewController 的大部分职责,慢慢也可能变的臃肿。

综合二者

来看下 Lancy 的设计,是如何将二者综合,规避缺点,保留优势的,先上图:

对于上图的说明:

  • 一个View Controller 持有一个 Data Controller。
  • Data Controller,是数据管理模块,负责数据的生命周期:获取、保存、更新。
  • 一个 View Controller 里面有多个 View,每一个 View 对应一个 View Model,这里的 View Model 概念和 MVVM 里的相似,惟一不一样的是这里的 View Model 和 Model ,没有绑定机制。
  • View 的展现样式,彻底决定于 View Model。

结合产品 UI,再按照数据流的方式阐述,如下面的 CollectionView 为例。

  1. View Controller 持有 一个 Data Controller,初始化以后,调用 Data Controller 获取用户打开的课程。(1)
  2. Data Controller 经过 API 获取数据,封装成 Model 并返回 (2,3)
  3. View Controller 将2中返回的数据,生成 View Model,调用 View 的 bindDataWithViewModel 方法装配给对应的 View。(4)
  4. View Controller 会调用 View 的渲染方法,View 经过 View model 直接进行渲染。(5)
  5. 若是有用户事件,经过代理的方式,传递给 View Controller,让View Controller 来决定下一步的处理。(6)

这么方式的优缺点:

优势:

  1. 指责分明,肯定给 Controller 肩负。
  2. 耦合度低,测试性高。指责分明带来的效果就是耦合度低,同一个功能,能够分别由不一样的开发人员分别进行开发界面和逻辑,只须要确立好接口便可。
  3. 学习成本低,不用事件绑定,不须要学习 RAC。
  4. 易于调试 Bug,不使用绑定带来的好处。

缺点:

  1. 当页面的交互逻辑很是多时,须要频繁的在 DC-VC-VM 里来回传递信息,形成了大量胶水代码。
  2. 没有绑定,带来额外的代码(绑定真的是双刃剑)

小结

针对这个案例,我以为最应该咱们思考的就是,做者 Lancy,在设计架构的时候的思路是怎么样的?为何要那么设计?是怎么取舍的?总结一下:

  1. 由于想让团队可以快速上手,以及bug能够快速调试,因此没有使用绑定机制。(从学习成本、开发成本、以调试角度)
  2. 依然保证了指责的明确划分。(好的架构必定要明确划分职责,甚至均衡的划分)
  3. 方便测试依然是重要的一个设计标准。(好的架构要易于测试)
  4. 还有至关重要的一个标准——解耦(好的架构要易于维护,解耦意味着比较易于维护)
  5. 上面提到了缺点之一是“当页面交互逻辑很是多时,会不太合适”,这也说明了,做者采用了这个架构,实际上是基于页面交互不是不少的状况(用户交互确实带来Model的改动不是不少,当前界面并不能修改用户所开的课程)。因此业务依然是影响架构设计的总要因素。
  6. 还有一点不知道你们有没有在乎,上面提到了“数据流”,对着这个架构咱们能清晰的说出“数据流”,这个我认为也是一个好的架构应该具备的特性。数据流若是很模糊,有不少分支,那咱们的维护成本将大大增长,一个清晰的数据流,意味着你不管在这个流的那个节点继续执行下需,都能获得正确的结果。

基于对这个案例的分析,最应该思考的是,设计一个架构的思路,换言之,你要内心明白,怎样才是一个好的架构。

总结

总结一下,今天说的这三个案例,其实就是为了说明一下几点:

  1. 懂业务对于架构的重要性。
  2. 架构 != MV(X),站在更加宏观的角度看问题,对于打开思路更有帮助。
  3. 当咱们设计架构的时候,怎样才是一个好的架构。

其实“架构”真的是个很大的话题,不少知识均可以拿出来单独学习和分享。

  • 设计原则和设计模式(设计的基本功)
  • 数据结构和算法(设计的基本功)
  • MV(X)/Viper
  • 组件化 (光这个就特别多能够讲的)
  • 网络层的架构设计(好比离散的仍是集约的)
  • 持久化层的设计
  • Hybrid 的设计
  • RN、Hot Patch
  • 无埋点
  • pod 私有库维护 SDK
  • 面向过程/面向对象
  • AOP
  • 。。。。。

但愿之后能陆续的为你们分享,擅长哪一个方向,或者对哪一个方向感兴趣的小伙伴也能够给你们分享一下,让你们的设计能力一点点提升上来。

参考

MVVM 介绍
https://objccn.io/issue-13-1/
被误解的 MVC 和被神化的 MVVM
http://blog.devtang.com/2015/11/02/mvc-and-mvvm/
iOS应用架构谈系列
https://casatwy.com/iosying-yong-jia-gou-tan-kai-pian.html
猿题库 iOS 客户端架构设计
http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/
饿了么移动APP的架构演进
https://www.jianshu.com/p/2141fb0dc62c
iOS应用层架构之CDD
http://mrpeak.cn/blog/cdd/
iOS应用架构现状分析
http://mrpeak.cn/blog/ios-arch/
iOS 架构模式–解密 MVC,MVP,MVVM以及VIPER架构
http://www.cocoachina.com/ios/20160108/14916.html

相关文章
相关标签/搜索