2015年入职XDF参与留留学iOS端的研发,至今,参与了好几个项目(留留学、掌上新东方、SL、乐听说等),最近负责乐听说iOS App端。不同项目的经历,让我接触到了不同的项目架构和代码风格,也让我对App的项目架构有所思考与心得。
1、App早期架构1.0
2015年6月留留学App iOS端1.0.0版本诞生,当时采用的架构很简单,就是在传统的MVC架构基础上,封装了一个网络服务层构建而成的,当时为了快速迭代上线,所以移动端App开发采用了“短平快”的MVC架构,架构如下图所示:
这种架构以层次结构简单清晰,代码容易开发而被大多数人接受,各层的分工如下:
- View层:显示层,负责UI的渲染。
- Controller层:作为View层和Service层中间层对上提供数据给View层展示,对下负响应用户的交互。
- Service层:业务层,负责APP业务逻辑封装,如预约课程等业务逻辑,对上层提供业务封装后的接口。
- Modle层:数据层,负责数据的包装、整理、解析等。
- mPass层:主要负责提供一些底层的功能支持,如数据库、拍照、分享等。
但经过几个版本的迭代,我们发现App所采用的MVC架构从Model-View-Controller走向了Massive-View-Controller的终点,其最严重的结果就是Control层的代码越来越多越来越臃肿难于扩展维护,同时Control层和View层之间存在一些较高的耦合。
这种架构在开发的后期会由于其超高耦和性,从而造就庞大Controller层,而这也是一直被人所诟病。
2、App架构2.0
基于上述遇到的问题,我们对原有的传统架构做了优化和调整,提出App架构2.0,并在留留学2.3.0项目中开始逐步重构采用MVVM分层架构,通过MVVM架构,可以有效实现Controller和View的解耦,同时使Controller轻量级,最终使越来越臃肿的Controller层逐步缩小并分解解耦,业务逻辑分模块下沉。
我参与的三个项目都是基于MVVM架构,包括:留留学App2.3.0,掌上新东方App等项目,现在以留留学、掌上新东方为例,留留学调整后的架构如下:
掌新架构如下:
各层的分工如下:
- View层:显示层,负责UI的渲染。
- Controller层:作为View层和ViewModel层中间层对上提供数据给View层展示,对下负响应用户的交互。
- ViewModle层:把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。
- Modle层:数据层。
- mPass层:主要负责提供一些底层的功能支持,如数据库、拍照、分享等。
通过MVVM架构,可以有效实现Controller和View的解耦,同时使Controller轻量级,但这种架构也有一些弊端,会让导致VM或Model中出现大量的基本业务处理、数据处理等,最后也会导致VM层变的臃肿,同时让Model层没那么纯粹,变的杂乱无序,所以还是需要进一步优化和剥离业务与数据的耦合。
3、App架构2.0+
也基于上述遇到的问题,我们对App架构2.0做了优化和调整,便衍生了App2.0+分层架构,采用MVVM+分层架构模式解耦,使越来越臃肿的Controller层逐步缩小并分解解耦,业务逻辑分模块下沉。由于留留学3.1.0之后就暂停了迭代,所以只对掌上新东方App 3.1.0之后的版本开始逐步采用MVVM+分层架构模式进一步解耦。调整后的架构如下:
各层的分工如下:
- View层:显示层,负责UI的渲染。
- Controller层:作为View层和ViewModel层中间层对上提供数据给View层展示,对下负响应用户的交互。
- ViewModel层:负责掌新APP业务逻辑封装,如预约课程等业务逻辑,对上层提供业务封装后的接口。
- Service层:负责具体的业务实现,包括对网络请求的封装以及请求后返回的数据的包装、整理、解析等,缓存等。
- Modle层:数据层。
- mPass层:主要负责提供一些底层的功能支持,如数据库、拍照、分享等。
对比2.0架构,我们是在ViewModel层和Model层之间插入了一个Service层,对于此次架构调整优点如下:
- Controller层只用来做中转层不参与业务逻辑等处理
- Controller层对上(View层)只提供页面展示所需数据,对下调用(ViewModel层)暴露出的业务逻辑接口
- 方便进行功能,业务逻辑的单元测试
- ViewModel层实现整个业务逻辑,实现对上层只提供接口因此此层灵活,易维护
- Service负责具体业务的实现,并对数据进行封装、整理等
对比1.0架构,我们是在原有的Controller层和Service层之间插入了一个ViewModel层,架构调整前后对比如下表:
App架构1.0 | App架构2.0+ |
---|---|
Controller控制层过于臃肿复杂 | Controller层只用来做中转层不参与业务逻辑等处理 |
老的Controller层包含了业务逻辑代码使此层的代码量超大并且臃肿不易维护 | Controller层对上(View层)只提供页面展示所需数据,对下调用(ViewModel层)暴露出的业务逻辑接口 |
Controller层包含业务逻辑不能较好,灵活的扩充,分隔等 | ViewModel层实现整个业务逻辑,实现对上层只提供接口因此此层灵活,易维护,具体的数据的包装等业务逻辑交个Service层 |
不能进行功能,业务逻辑的单元测试 | 方便进行功能,业务逻辑的单元测试 |
4、App架构3.0
都是基于当前我参与的乐听说基于2.0+架构采用swift开发的口语评测App,留留学、新东方、乐听说App等现有架构可实现内部竖向解耦,后续开发中我们将逐步实现各个层同层内部子模块的解耦工作(横向解耦);同层之间各个子模块之间调用相互依赖,会严重影响各个模块之间的解耦,如A模块内部(甚至外部)依赖B、C模块,而B、C模块又依赖A模块,这种相互依赖、相互include的情况导致各个模块相互不能独立,严重影响编译速度和扩展性、灵活性等, 在后续版本中为了完成横向解耦我们内部将开发实现一个动态路由组件(DR,Dynamic Route),以乐听说为例进行说明,如下图:
路由实现方案简图如下:
5、模块化结合Pods
参与的项目基本都是采用模块化开发,尽量实现高内聚低耦合,以掌上新东方为例,App研发模块以及对接平台众多,我们采用MVVM架构(后期采用MVVM+架构)进行模块化开发,实现工程的可扩展性以及易维护性,尽量做到高内聚低耦合。如下图:
当公司里面有多个项目同时进行,并且有可能是多个人分别不同项目时,就会存在相同模块重复开发,其实每个APP中都是有很多共同的模块,当然有可能你会把相同功能模块代码复制一份在新项目中,但这其实并不是最好的方式,在后期不断迭代过程中,不同的人会往里面增加很多带有个人色彩的代码;这样就像相同的模块项目后期对于多个项目统一管理也是灾难性,有可能会失控,哪怕项目转移别人接手也会无形中浪费很多时间,增加维护成本,所以实例中更注重对于一些相同模块进行提取,求同存异。
我们将尝试采用模块化结合Pods进行管理,对于常用功能的封装,只要开放出一些简单开关配置方式,就可以实现一个功能,比如日志记录、网络请求模块、网络状态变化提示等。
将分OC和Swift语言开发两套对应的路由组件,会优先着手OC版本的研发,由于之前都忙于项目开发,近期会抽时间对代码进行完善(LLRouter),如有好的思路和见解,可以给我提issues,核心代码如下图:
6、总结
App架构以及相关性能的优化不是一蹴而就的,需要不断的探索和钻研!同时架构没有真正的好坏之分,只要适用于自己的业务,就是好的架构!
以上只是我的一些心得和感悟,肯定有一些地方需要完善,如有不对或不恰当,望大家留言讨论!