iOS - 组件化

243 阅读6分钟

Balanced distribution of responsibilities among entities with strict roles which withstands changes over time.

背景

随着产品的迭代,项目代码结构的依赖关系的变化如图所示

业务价值

  • 复用

    • 很多公司的产品是多个APP,或者多个不同地区的APP区分开,组件化可以抽离和复用基建
    • 使用配置化的方式,使用相同的基础组件,快速开发近似APP
  • 编译

    • 以某些标准把APP的迭代划分成不同的实体区域,细分来看部分功能和代码在不断迭代,另外一部分总是不变。那么把变化的部分抽离出来,迭代之后单独重新编译,而不是整理重新编译,可以大幅减少编译的时间
    • 对如基础组件等很少变动的组件,打成二进制包,大幅减少宿主编译时间
  • 隔离

    • 多数APP由不同的几块业务组成,比如交易、社区、发布工具、个人中心、直播等业务线。组件化抽离基础依赖之后,这些业务的开发隔离开后可以模块内独立开发

    • 代码隔离保证了可测试性

技术方案

依赖解析

图形解析

Podfile.lock文件以YAML格式记录了组件的依赖关系,我们通过脚本对该文件做解析

依赖树

组件作为重复结点

依赖图-拓扑排序

组件作为单一结点

影响树

修改某一个组件的时候,受到影响的依赖组件形成的影响链路

分别以PremiumUtils组件和MarkdownFeature组件为例

依赖指标

依赖深度

从依赖树来看,依赖深度就是树的深度。

被依赖个数

从依赖树上来看,被依赖的个数就是组件出现的个数。

从拓扑排序依赖图上来看,被依赖个数就是该组件顶点的入度。

组件发版版本号变化或者Public API修改时,被依赖的个数表示组件接入更新时需要修改的依赖组件数。

组件划分

层次划分

  • 组件类型

    • 业务模块依赖基础业务组件,基础组件。基础业务组件依赖基础组件。不可反向依赖。不可循环依赖,同层依赖需要解耦。

    • 业务模块
    • 基础业务组件(自定义的基础组件,在部分业务模块之间复用)
    • 基础组件(完全复用)

从底层往上层是复用性到易用性的渐变,所以基础组件复用性强,可以在任意APP间复用,易用性弱。基础业务组件易用性强,已经包含了部分业务需要配置,业务模块只需要添加简单的配置即可,复用性弱,只能在公司内部分APP间复用,整体更像是外观模式。

  • Change Often

    • Change Often
    • Change Rarely

如果开篇所说的好的架构可以承载随着时间的变化,从项目迭代中来看业务模块的开发和迭代是最迅速的,业务线团队需要跟产品直接对接。而基础组件和抽象能力的建设,比如网络库日志库等变化是很少的。

实体划分

团队组织架构

团队的分工协作取决于于信息传递效率和透明度,团队过大之后信息杂乱会导致信息传递效率降低。

通常iOS团队结构,通常业务架构负责基础组件的维护,或者业务团队是部分基础组件的Owner.

  • 业务架构组/Infra(组件化/组件维护/性能优化-包大小/启动)(6人左右)

  • 各个业务线/BU(4~10人)

  • *移动端平台/中台架构组/Platform(CICD/APM)(4~10人)

实体定义

代码主要是配置和代码

把组件分成Public API和Private API两个部分,或者说是抽象能力和具体实现两个部分。组件的依赖可以看成是Public API的耦合。

  • Public API

  • Private API

  • 抽象能力

  • 具体实现

数量

从基础组件到基础业务组件是从复用性到易用性的转变,如果以单个API为独立实体,职责就极端单一,逻辑闭环,复用性看起来更好。如果是这样的话,那么会产生数量庞大的组件数量,比如几千个组件。几千个组件会导致组件无法复用,因为难于管理和寻找。

上部分列出了iOS团队结构也是为了说明组件数量不宜过多,8个架构同学面对40个基础组件还能维护过来,但是如果面对200个?业务同学面对40个基础组件,个位数的基础能力区分,还能使用过来,如果多大几百个,在没有一定机制比如脚本或者平台的保障下,索引就成了问题。

资源管理

工作流程

组件发版

组件基于各自的Example开发

Git

基于Master做发版操作,PR需要Module Owner Review

Spec管理

可以使用同一个spec源,可以按照不同的约定分源管理

版本管理-语义化

组件化之后,项目可以通过配置组件的版本号来管理各个版本的接入。如此的情况下,原本直接是代码的Diff就变成了版本号的Diff,代码和功能的迭代变化变得更加不直观。通过对组件版本号做语义化功能化可以改善这部分的问题

"~>0.1.0"

发版

手动发版命令
pod repo push YourSouceSpec --source="YourSource" --allow-warnings --verbose
发版顺序

涉及到多个组件发版,需要按照发版顺序执行,被依赖的组件先发版。

发版的常见问题
  • spec写法

CICD

  • 时机

    • Gitlab-CI Trigger
    • 往Master合PR
    • 其他
  • 操作

    • Pod repo push

宿主集成

  • 宿主集成统一在Podfile中对组件的版本进行"~>"的约束,不在spec中对版本做限定

  • 在宿主APP流程的关键节点,需要确认Podfile.lock中组件版本号的变化

  • 基础组件的大版本集成需要由基础组件Owner对所有依赖其组件的依赖方做统一接入的推进

*组件管理平台

GUI化的平台其实可以进一步提升易用性,组件管理平台可以组合权限管理,权限审批,组件内容变更,组件版本号确认等功能。

引用