iOS 客户端组件化之路

 

前言

随着业务的发展,产品的需求不断的增加,功能模块越来越多,开发人员逐渐膨胀。因此明确职责分工,剔除冗余结构,避免重复工作,减少多人合作冲突变成了非常重要的事。而组件化就是完成这些目标的一种方案。

目前市面上对组件化方案对讨论也有了很多,但是大多都只局限在路由这块,本文将阐述我对组件化项目的思考和演进路线的安排,希望大家能多多给出建议和意见,共同完善我们的产品。

范围

组件化在前端已经是一种非常常见的架构方式了,后端也有类似的微服务。但是客户端这边目前还是处于不太成熟的阶段。组件化的本质就是从混成一团麻的项目中,抽离出具有高度复用性的模块。因此在说明组件化方案之前,我们需要先描述组件化的范围。

目前公司的 iOS 端的结构如下:

目前主要存在的问题有以下几点:

  1. 业务之间横向依赖较多,甚至有交叉依赖,改动一处牵动全身
  2. 业务中 UI 与数据之间没有做到相对解耦,数据复用比较困难,没有 Model Layer,持久化方案难以执行
  3. ViewModel 功能不足,只做了网络数据处理和异常处理,数据传递、消息转发完全通过 RAC 实现,但却没有直接转为 View 所需的数据源。
  4. Service/Manager 功能划分不明确,容易造成语义理解错误,部分功能没有做成 Service 的必要,单例对象过多====
  5. 基础公共层太臃肿,基础服务被业务直接依赖,有反向依赖
  6. 没有统一的消息传递协议,缺少组件间调用中间件

针对以上问题,我们需要根据现有的业务情况进行架构调整,按照分层结构我大致划分了如下四层(该分层为功能依赖分层):

根据该分层结构,将组件化的构成分为四个部分:

1. 基础组件: 这部分由项目所需的基础服务库组成,包括网络库安全加密库语音引擎库数据库三方sdk等,这部分组件的特点为组件之间必须完全独立,不含任何横向依赖,绝大多数情况下业务层不可直接使用

2. 核心组件: 这部分主要是由基础组件组合成的弱业务组件,提供多业务线的共通功能,如push组件JavascriptBridge组件社会化分享及三方登录组件UI控件组件持久化组件等,这部分组件需要尽量避免横向以来,API 需要尽量精简,并可以供业务层直接调用

3. 容器通道组件: 这部分本来应当属于核心组件的一部分,但是为了未来的三端统一调用的目的考虑,将其独立为一层。该层由各种消息发送、数据传递管道的封装为主,包括WBLinkerWBPipelineWBErrorHandlerWBRemoteCallHandlerWBGameContainer等,这部分组件与核心组件的依赖关系类似,在此不再赘述

4. 业务组件: 这部分是组件化的主要部分,前面三层的拆分都是为了该层做准备。本层的特点是组件之间必须完全解耦,解耦方式可以在容器通道组件中选择,本层可以直接调用核心组件,但不允许直接调用基础组件,该部分的概念描述可以参考这个链接。 这四层其中无论哪一层,都是通过 CocoaPods 进行组合。每个 Pod 都可以独立编译独立执行,独立进行测试。每一个项目完成时,只需要做集成测试即可。

方向

组件化的过程不是一蹴而就的,是一个长期的架构演进的计划,因此设计出合理的实施方案还是很有必要的,我提出以下几条作为纲领:

  1. 组件化的进程,应当在业务层之下使用自底向上的方式逐层推进
  2. 业务层则使用接口共存、平滑兼容的方式,逐个模块递推下去,逐步替换掉旧代码的方式进行
  3. 破坏性的重构工作应当尽早进行,尽快完成,尽力完善,一旦确定就避免二次修改,直到下一次的架构演进
  4. 基础服务应做到足够的单元测试覆盖率,保证服务的稳定性
  5. 接口部分需要提供足够的注释,减少同事间接入熟悉的时间

路线

由于现有的业务量还是比较多的,直接从业务层入手也不太符合实际。

我建议先从基础组件开始抽离,如网络库、安全库、语音库、数据库等。这些组件根据业务情况设计完成后替换掉现有代码,并完成集成测试后,再做核心组件层。

核心组件根据业务情况可以适当的和业务层一起重构,核心层的本质是可复用的弱业务层,因此两者之间的界线并不一定明显,这个得需要根据实际情况来做调整。

业务组件之间的调用必须通过容器通道,与核心组件之间的调用,视情况而定,建议尽量选择使用容器通道,如果实在不方便,直接调用也是可以接受的。

结语

本文仅从架构依赖和功能调用上阐述组件化的设计,除此之外还应当有数据流动的架构设计和业务组织的架构设计,本文暂时不做讨论。

一个架构的演进,最理想的方式就是渐进式的软着陆演进,但是革命的过程必然不是一帆风顺的,中间遇到的困难也是可以预期的,希望大家可以携手并进,破除万难,以让公司成为业界一流架构的 App 而努力。