App架构二三事

4,610 阅读12分钟

一、概述

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 不会被重用的业务模块,可以粗放式划分,不必投入过多精力,优先保障业务进度;

  • 容器层

    • App生命周期、事件分发等管理:
      • 实现一对多的消息分发,类似于iOS的通知中心 or Android的发布/订阅机制(EventBus)
    • 组件间通信
      • URL路由:通过URL唤起服务;iOS可参考MJRouter、、Android可参考Arouter
      • 中介者:通过中介者实现组件之间通信,组件和组件之间无依赖,无耦合;iOS有CTMeditor
      • Procotol Class绑定:定义组件提供服务的协议,具体由组件实现;组件和组件之间有依赖,但是耦合低;IOS有BeeHive
  • 组件集成:壳工程中保留工程配置选项依赖库管理文件;利用组件管理工具将组件集成在一起,iOS可以CocoaPods、Android可以用Gradle;

4、组件化后变化

  • 多组件工程开发:每一个组件对应一个工程,每个需求会修改多个组件工程的代码和资源文件;
  • 多业务团队协作:不同组件交由不同团队 or 个人负责,App每个版本都涉及多个团队之间协作;比如某个版本需求,直播间新增一个登录后可以发红包功能,这里面会涉及到支付团队,直播团队还有UG团队之间的协作。
  • 并行开发:App每一个版本对应不同组件工程修改,这些个组件工程合并在一起称为基线;每次封版之后,参与下一个版本迭代的同学都需要基于稳定的基线做开发。

5、完善基建的诉求

  • 建设 多工程代码管理工具,支持多工程clone、commit、push和merge等基本操作
  • 建设 多工程MR管理平台,支持不同组件工程代码lint、工程合码、发版和集成;
  • 建设 组件库管理平台,支持管理各组件的的源码&二进制、依赖、升级和发版等;

​ 组件化后,基础建设未完善之前,明显到开发效率降低;甚至怀念当年单工程时代;从另一方面也说明,基础建设能力完善,也能很好推动架构的演进;

三、App架构-架构模式

架构模式:指导设计程序的结构,目前常见的架构模式有:MVCMVPMVVM

1、Apple MVC 介绍

  • MVC(Model–View–Controller)分为三个基础部分:模型(Model):模型层,数据及其处理;视图(View): 视图层,UI展示和交互;控制器(Controller):响应用户输入,并通知模型、视图更新。MVC有经典MVCApple MVC,Apple MVC和经典MVC最大的不同是,Apple MVC隔离View和Model的通信

Apple-MVC

  • Apple MVC中,Controller持有View和Model,当Model发生变化时候,可以利用通知、代理或KVO(iOS特有)等方式通知Controller;Controller可以直接根据Model来决定View的展示。View接收到响应事件, 通过delegatetarget-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

  • 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

  • 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 深度实践探讨

支付宝客户端架构解析:Android 容器化框架初探

Android组件化方案及组件消息总线modular-event实战

美团外卖iOS多端复用的推动、支撑与思考

组件和模块的区别

组件化架构漫谈

解读 iOS 组件化与路由的本质

MVC、MVP、MVVM的演化

Model-View-ViewModel for iOS

iOS 组件通信方案