组件化思考和落地

前言

随着我们业务发展,参与业务开发的同学也逐渐增多。为了适应新要求,需要对旧的架构做一次升级。组件化是架构升级中的重要一步,将业务模块进行组件化,将各个业务的逻辑和依赖梳理清楚,才能有效降低业务迭代带来的复杂度,为后续更复杂的优化做铺垫。

正文

问题背景

iOS的App架构早期设计分为三层:业务模块层、基础业务层、基础功能层。



业务模块层承载具体业务模块,基础业务层封装业务基础能力,基础功能层桥接依赖的Pod库。
随着业务的发展,SSCommon基础功能层接入越来越多的功能库,SSFoundation基础业务层沉淀出来BDNovelKit、BDNovelWidget、阅读器SDK和听书SDK,SSApp业务模块层也在不断生成新的功能模块。

经历多个版本的迭代,存在几个较为明显的问题:
业务模块依赖无抽象,以主Tab和分类业务模块为例,既没有主Tab要求分类业务模块实现的TabProtocol,也没有分类业务模块要求宿主实现的Delegate;
层级界限不清晰,当新增某个功能业务时,对应数据结构类型、业务组件等全部放在业务模块层;
业务模块调用不规范,比如说在书城模块需要使用其他业务模块(搜索、有声、金币)时,会直接引入的对应业务模块实例;

问题解决

组件化的目标是逻辑内聚、依赖抽象。
将复杂的工程,拆分为若干个独立的组件,将复杂的逻辑内聚,仅对外暴露接口,降低整个工程的复杂度。同时也是方便后续工程进行拆分,对于部分业务进行子仓化,部分通用的基础组件甚至可以多App复用。

通用基础层

使用范围不局限于App的基础库,既有公司提供的Heimdallr,也有自己维护的BDReader。

业务基础层

仅服务于自己业务,会被上层业务直接使用,包括SSBook这种业务基础数据结构,也有业务通用的SSBaseView,这些代码会封装到若干个Pod库。

业务接口层

业务接口层主要是描述每个业务组件的接口,调用组件应该通过接口去调用,接口层是组件生成必备。

业务实现层

业务实现层是接口层的具体实现,组件化之后的业务组件主要逻辑放在这里,实现层是组件生成必备。

主App

目前整个App大部分逻辑都是放在这里,随着组件化的推进,逐渐沉淀部分逻辑到业务实现层、业务接口层和业务基础层。

具体组件

以分类组件为例,这是分类组件的大致构成。



SSCategoryImp可以直接使用业务基础层的SSBook和SSBaseView,也可以使用通用基础层的BDALog和Heimdallr。
主App会通过SSCategoryInterface去调用分类组件,同时也会实现一个SSCategoryDelegate,作为分类部分功能的回调。

标准实现

组件内部也要分层,便于后续组件管理,以及组件间能力复用。分层建议包括组件接口层、组件实现层、组件基础层、组件数据层。
组件接口层:存放组件对外提供能力的抽象接口;
组件实现层:存放组件对接口实现的具体代码;
组件基础层:存放组件对外提供的业务UI能力;这部分复用组件较多之后,需要下沉到App的业务基础层;
组件数据层:存放组件对外提供的业务Model;这部分复用组件较多之后,需要下沉到App的业务基础层;

问题延伸

模块化

在我们的工程里,模块化指的是将业务功能模块拆分成若干个功能模块,模块可以在多个业务中复用。比如说某个书评业务使用评论组件、点赞组件、气泡组件等进行模块化编程。模块化编程可以有效提供代码的复用率,同时也便于沉淀组件。

代码分仓

直接分仓会存在增加开发成本和维护成本的问题,短期组件化会有较多改动。但是分仓又是一种比较好的物理隔离方式,可以减慢代码劣化,同时也比较方便管理依赖。待组件化成熟之后,再进行代码分仓。
业务基础层可以直接沉库,方便建立明确的层级关系。

组件通信

组件通信其实就是组件A调用组件B的某个功能,这里有几种方式,以分类组件和播放组件为例。
接口调用:分类组件有业务逻辑需要感知当前正在播放的书籍id,那么应该通过播放组件提供的抽象接口(而不是播放器实例),拿到这个书籍id;
依赖注入:分类组件描述需要依赖外部实现的能力并提供注入接口,然后外部组件再主动通过接口注入该能力的实现;
消息通知:播放组件在切换当前播放书籍时,可以通过消息通知所有关注的业务组件,业务组件Register的Message是在业务基础层;

落地规划

阶段一 基建准备

工程梳理,明确基础业务层范围,业务基础层搭建;
接口层实现和组件注册机制;
基础工具支持准备,组件调用能力;

阶段二 show case

业务落地,以某个业务做组件化,打造show case;
组件化结构合理,包括接口、数据和实现;
搭建配套的检查、review、多仓合码等机制;

阶段三 业务组件推进

降低改造成本,并逐步推广到多个业务;

组件化思考

分仓实现有哪些问题?

依赖版本管理问题,组件本身需要和主端App保持一致依赖版本号。
拆分组件之后,如果使用分仓隔离,则不能直接操作组件,需要引入多仓开发。

组件有哪些类型?

按照使用范围有:
通用组件,多端App都能用的组件;
业务组件,只有当前业务使用的组件;

按照内容区分:
功能组件,业务的具体业务组件,着重点在于逻辑内聚,代码隔离;
基础组件,业务的基础功能组件,着重点在于功能的重复利用;

业务组件由哪些组成?

代码+资源+依赖+抽象。
代码:承载具体业务逻辑的.h/.m;
资源:业务使用的图片等其他资源;
依赖:组件需要主App实现的能力;
抽象:组件提供给主App使用的能力,也就是接口层,接口层包括方法和数据类型;

业务组件的有哪些实现方式?

Development Pods,组件代码和主工程代码同仓;
Pod库,类似第三方库,代码分仓;
子工程依赖,业务组件单独成为一个工程,被主工程依赖,代码同仓;
文件夹分隔,同一个主工程,用不同文件夹分隔,通过添加文件夹Reviewer来避免劣化,代码同仓;

所有的代码分仓,都需要考虑业务组件和主App的依赖版本一致问题,有些成熟业务会有业务组件容器化的解决方案,可以把业务组件和主App的pod版本对齐。
代码分仓带来了另外一个问题是工程配置、宏定义、xcconfig等不同步,需要及时打通和更新。

比较好的实践是综合上述的过程:
1、先梳理依赖,再用文件夹做简单分隔;
2、对应文件夹用Development Pods进行分隔,这一步也可以用子工程来实现;devPod相对简单,但是无法完全隔离;子工程可以物理隔离,但是维护相对麻烦;
3、Pod子仓,明确组件的subspec和podspec依赖;

业务组件如何感知App生命周期?

目前并不打算让主App对系统事件进行封装,App生命周期、Push处理、系统事件处理等由主App处理,各个组件可以直接去监听系统的事件。但有些事件只会回调到主App,那么再由主App分发事件。
待到组件化足够成熟,可以把主App再拆出若干个负责事件转发的底层组件,作为通用的依赖(容器层)。

接口层如何屏蔽具体的实例?

需要有组件的接口和绑定方法,这里用到了一个公司内部提供的库来实现,基本原理还是通过MachO段来做绑定。
组件外通过GET_PROTOCOL(SSProtocol)和GET_PROTOCOL_CLASS(SSxxProtocol) 两种方式来调用,组件内通过BIND_PROTOCOL_SERVICE(SSProtocol, SSxxImpl)来绑定接口和实现。

总结

网上关于组件化的文章非常多,这里主要介绍我们业务的思考和落地过程。
架构优化是一件持之以恒的事情,技术方案总是可以持续完善。最初的设计不用太复杂,逻辑清晰便于演进架构,能解决当下协作痛点,适应业务迭代的节奏,就是一个好的解决方案。

代码架构,合久必分,分久必合。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容