Table of Contents
一、概述
1、架构 & 架构师
- 架构一词源于建筑学,原指建筑物在其尺度上,依靠内部支撑物相互结合,而稳固构造的方式。
- 在软件行业中,架构可分为:业务架构、应用架构和技术架构;其中,业务架构是最顶层的设计,技术架构是基建,而应用架构承上启下:上承接业务架构的落地,下决定技术的选型。
- 我们接触最多的是应用架构,主要职责:拆分(边界划分)系统/模块/组件,定义各组成成分之间的分工和合作;平衡业务、技术和团队的复杂度;最终目的是保障业务顺利落地。
- 架构师们需要先了解业务架构;然后根据业务架构,设计相应的应用架构,最终推动应用架构落地,升级和完善技术架构;因此,架构师的职责可以归纳为:**理解业务、全局把控;技术选型,解决关键问题、指导技术落地实施 **。
2、衡量架构的合理性
- 架构是为业务服务的,没有最优的架构,只有最合适的架构;一般从业务需求角度 和非业务需求角度来评估架构的合理性。
- 业务需求角度
- 能解决当下业务需求和问题
- 能优雅且可复用地解决当下绝大部分业务问题
- 能适应未来一段时间内的业务迭代,而不会因业务大量迭代要大改甚至推翻原来架构。
- 非业务需求角度
- 稳定:服务稳定,如App的Crash率万分之五,OOM率万分之一,后端服务可用99.99%
- 安全:数据和代码安全等
- 高效:功能可扩展、功能高复用
3、前后端架构
- 移动互联网时代,前后端分离的背景下:大前端(前端、移动端)关注交互体验,后端关注高并低延,这些都导致前后端的架构方案走向完全不同的道路。
- 后端应用架构发生了从单体应用->分布式应用->微服务的演进;微服务架构通过更细粒度的服务和设计准则来实现大规模、复杂的后端应用架构设计。
- 大前端应用架构发生了从单工程->组件化的演进,组件化架构采用独立组件的方式,实现了工程和代码的解耦,适合复杂业务中,多团队之间的分工和合作。
- 虽然微服务和组件化是两个完全不同的领域,但是核心目标却一致:分离业务(组件/模块/系统)的边界和责任,保证各组成成分的独立部署、维护和升级,最终由聚合在一起,服务于用户。
- 前端项目在组件化之后,也慢慢吸收微服务思想,演化出微前端架构,业内有一些尝试,如:前端微服务在字节跳动的落地之路。
二、App架构-组件化
1、概述
- App架构指的是App的应用架构,是服务于业务架构的一部分;在App的应用架构中,主要关注以下两点:
- 职责划分:逻辑分层,组件划分,明确各层级、各组件之间的边界和责任
- 职责协作:定义层,组件对外提供的能力,规范层与层之间,组件和组件之间的协作(调用)关系;
- App架构中的分层是横向划分,可以将App应用划分成N层,具体的组件分割在不同层中,每一层保持内聚性,并且与它下面的各层保持松散耦合。
- App架构除了定义好职责划分和协作,还需要以下一些内容:
- 开发技术选型:开发语言,框架和工具
- 架构模式:MVC、MVVM
- 开发/编码规范
2、现状
- App一般分iOS和Android两端,除了平台特有的一些特性,大体架构其实是差不多的;分层、组件化、开发架构模式等都是可相互借鉴的。
- Android在组件化基础上,利用插件化实现功能的动态下载和更新;但是由于苹果对动态化的限制,iOS插件化实践非常少。
- 大型的App项目,组件化落地后,代码、业务职责更加清晰了,不同的组件由不同团队or个人维护、升级;然后职责的分散依然需要服从统一的规范和管理,否则代码质量、开发效率等难以避免发生劣化;
- 很多小App项目,建议有选择地实践组件化,盲目推动组件化,可能会给开发人员带来负担,降低开发效率,拖累业务发展。
3、组件化简介
- 三层架构 + 组件拆分 ;从上到下层级可以是:业务层、容器层 和 基础层;将项目拆分成不同组件(一个组件可以是一个单独的工程,隔离代码和资源,可以独立编译和运行),每个组件在不同的层级。层级可以是:
- 业务层:各类业务组件,如用户登录、分享、直播等业务组件。
- 容器层:架构的核心,为应用提供App生命周期管理、事件分发,负责组件间的调度和消息派发。
- 基础层:主要是基础组件,包含基础库,如网络功能、图片加载,性能监控,数据存储,日志系统等。微信支付宝SDK;
选择合适的粒度拆分组件;业务变更很快 or 不会被重用的业务模块,可以粗放式划分,不必投入过多精力,优先保障业务进度;
- 容器层
- 组件集成:壳工程中保留工程配置选项和依赖库管理文件;利用组件管理工具将组件集成在一起,iOS可以
CocoaPods
、Android可以用Gradle
;
4、组件化后变化
- 多组件工程开发:每一个组件对应一个工程,每个需求会修改多个组件工程的代码和资源文件;
- 多业务团队协作:不同组件交由不同团队 or 个人负责,App每个版本都涉及多个团队之间协作;比如某个版本需求,直播间新增一个登录后可以发红包功能,这里面会涉及到支付团队,直播团队还有UG团队之间的协作。
- 并行开发:App每一个版本对应不同组件工程修改,这些个组件工程合并在一起称为基线;每次封版之后,参与下一个版本迭代的同学都需要基于稳定的基线做开发。
5、完善基建的诉求
- 建设 多工程代码管理工具,支持多工程clone、commit、push和merge等基本操作
- 建设 多工程MR管理平台,支持不同组件工程代码lint、工程合码、发版和集成;
- 建设 组件库管理平台,支持管理各组件的的源码&二进制、依赖、升级和发版等;
组件化后,基础建设未完善之前,明显到开发效率降低;甚至怀念当年单工程时代;从另一方面也说明,基础建设能力完善,也能很好推动架构的演进;
三、App架构-架构模式
架构模式:指导设计程序的结构,目前常见的架构模式有:MVC
、MVP
和MVVM
;
1、Apple MVC 介绍
- MVC(Model–View–Controller)分为三个基础部分:模型(Model):模型层,数据及其处理;视图(View): 视图层,UI展示和交互;控制器(Controller):响应用户输入,并通知模型、视图更新。MVC有经典MVC 和 Apple MVC,Apple MVC和经典MVC最大的不同是,Apple MVC隔离View和Model的通信;
- Apple MVC中,Controller持有View和Model,当Model发生变化时候,可以利用通知、代理或KVO(iOS特有)等方式通知Controller;Controller可以直接根据Model来决定View的展示。View接收到响应事件, 通过
delegate
、target-action
等方式告诉Controller的状态变化。 - Apple MVC中,一个典型UI交互的过程:
- View接受用户操作发送给Controller;
- Controller根据操作对Model进行修改;
- Controller接受Model修改的通知,并根据通知更新对应的UI;
- Controller层膨胀(Model-View-Controller -> Massive-View-Controller)的原因有二:
- Controller持有View和Model,几乎可以控制所有逻辑,随着Controller和Model、View的通信越来越多,Controller中代码也越来越多;
- 一般情况下,Android的Activity,iOS的ViewController 即当View层又当Controller层,并没有将View层 和 Controller层进行分离;这些都加剧了Activity/ViewController的臃肿。
- 此外,厚重的Controller很难测试,不管是手动测试或是使用单元测试,因为有太多可能的状态。为解决Controller臃肿问题,衍生出MVC的变种:MVP和MVVM.
2、MVP 介绍
- MVP(Modell-View-Presenter)主要有三部分Model、View和Presenter,其中View持有Presenter,Presenter持有Model,和Apple MVC一样,View和Model是不通信的,具体的控制逻辑在Presenter,Activity/ViewController主要作用是响应生命周期和显示UI。
- MVP模式解决了Controller的臃肿问题,使得软件结构更加清晰,真正意义上的将UI逻辑和数据逻辑隔离了,Presenter层和Model层都可以做单元测试;
- 但是MVP模式下,Presenter层不仅有控制逻辑,还有大量View->Model,Model->View的同步逻辑,造成Presenter比较臃肿。
3、MVVM介绍
- MVVM(Model-View-ViewModel)主要有三部分:Model、View和ViewModel,其中View持有ViewModel,ViewModel持有Model;View和Model是不通信的,具体逻辑在ViewModel;
- MVVM使用一种双向绑定机制,使得 Model 变化时,ViewModel 会自动更新;而 ViewModel 变化时,View 也会自动变化;
- 在实现双向数据绑定方案上,iOS可以使用 KVO 或 Notification or ReactiveCocoa框架;Android可以使用Google提供的DataBinding;
- MVVM模式降低了View和Model之间的耦合;分离了业务逻辑和视图逻辑;可解决MVC模式中Controller过于臃肿,MVP中Presenter过于臃肿;
- 但是MVVM模式下:View和Model双向绑定导致bug难以定位,两者中的任何一方出现问题,另一方也会出现问题;
ReactiveCocoa是个很好的框架,很多iOS团队使用ReactiveCocoa框架来实现数据的双向绑定 ;但是鉴于ReactiveCocoa学习和维护成本比较高、只是做双向绑定有点大材小用,我们是个用了更轻量级的KVOController
四、iOS组件间通信方案
iOS组件之间通信一般采用三种方案:URL路由、Protocol Class绑定、中介者;
1、URL路由
- 简介:
- 根据URL注册对应的服务,然后通过URL调用;
- iOS经典实现:蘑菇街的MGJRouter;提前注册好URL 和 服务Block & 参数字典的对应关系(保存在router字典中),然后利用URL找到对应的Block,将参数字典交给Block,唤起对应的服务。
- 特点:
- 使用简单,非常适合统一Android和iOS双端页面跳转,对项目运营帮助很大;
- URL路由不适用调起埋点、日志上报、Network请求处理、图片加载,数据存储等等基础组件服务;
- 注册分散、参数字典不方便传递比较复杂的参数,如UIImage、自定义Model等;还需要专门维护URL;
2、Protocol Class绑定
- 简介:
- 面向协议编程,定义好服务协议,具体由组件实现;组件依赖的是协议,而非具体实现;
- iOS经典实现:阿里的BeeHive;提前注册Protocol+Class的对应关系,然后根据Protocol获得对应的实现Class,获取对应的服务;降低了模块之间的耦合;具体可见BeeHive —— 一个优雅但还在完善中的解耦框架
- 特点:
- 通用性比较强,协议和实现分离,直接依赖协议即可;
- 缺少统一调度层,难于集中管理;无法避免对协议类的依赖;
3、中介者
- 简介:
- 使用中介者统一调度组件间通信;
- iOS经典实现:Casa的CTMediator;业务上定义好服务方法,方法内部通过performTarget方法调用服务方组件的Target、Action,利用Runtime实现解耦;
- 特点
- 中介者能实现统一管理组件服务;
- CTMediator实现上,需要明确Target、Action符号名,需要很多硬编码;编译阶段不检查,运行时才检查对应类或者方法是否存在。
4、总结
- URL路由和Protocol Class绑定都需要在注册后,才能提供服务;
- URL注册本质是使用
字符串常量
代替原有的函数声明,这样就不用引用头⽂件,但是因为没有函数和参数声明,影响业务使用效率;而Protocol Class绑定提供了函数和参数声明,方便业务理解和使用,但是组件使用时,需要依赖协议; - 在对组件服务管理上,中介者比URL路由和Protocol Class绑定有更强的控制和管理能力;
- 三种通信方案都是为了解耦组件;而解耦并不仅仅为了实现编译上解耦(如,组件间文件无引用),更多是为了:分离业务逻辑和职责;因此,在业务中,根据实际情况选择方案;架构方面,更多的精力是在:保证上下层依赖清晰、组件间调用清晰。
历史文章
参考文章
开篇 | 模块化与解耦式开发在蚂蚁金服 mPaaS 深度实践探讨
评论前必须登录!
注册