我所理解的组件化之路

为什么会有这篇文章呢?

和之前的同事"我是你爸爸"讨论了关于组件化的事,对我有很大的启发。在此特别感谢"我是你爸爸"。

最近写了关于组件二进制化的文章的文章,有点感触。

一些朋友来问我关于CocoaPods的问题提到了组件化。

自己一开始准备写《组件化之路》的博文的,但是后来发现我的理解是有偏差的。

以上,所以我想写一篇关于《我所理解的组件化之路》的博文来阐述自己的观点。

先提出一个新词,我自己想的。叫做“CocoaPods化”或叫做“library化”

什么叫做CocoaPods化?

CocoaPods化也就是我们公司正在做的。随着业务的扩展,有了多个App,有了多个Team,我们希望把一些代码重用。使用CocoaPods把他们做成library是个很好的选择。也可以说是CocoaPods化之路。

1.和业务无关。
开始做这件事的时候,我们会容易的想要把那些Util、Category、JSBrige等等这些和业务无关的源码搞在一起做成一个一个CocoaPods库。它们变成了YTXUtilCategory、YTXWebViewJavaScriptBridge、YTXNibBrige、YTXAnimations这些库。

2.弱业务
接下来,进一步地我们会把那些比如网络请求、Server配置、行情图、行情Socket等等这些弱业务的源码搞在一起。她们变成了YTXRequest、YTXServerId、YTXChart、YTXChartSocket、YTXChatUI等等。

为什么说是弱业务呢,稍微分析下。比如YTXRequest、YTXChartSocket、YTXServerId在公司内部各个App,各个Team之间是通用的,在各个业务组件之间可以重用和组合使用;又带着鲜明的公司特色,没法直接开源了就能让其他开发者使用。

如果只做到了前2步,我觉得不能称之为组件化。只能叫做CocoaPods化或Library化。

3.业务
这一步,到目前来说没有做。所以没法举我自己实际的例子。

比如拿美团App做例子来说。一条业务线是外卖,一条业务线是电影。分别由2个Team维护开发(技术,产品,测试等)。有各自的KPI。这两条业务线是自洽的,是分治的。

外卖是一个业务组件,电影也是一个业务组件。里面包含了各种内容,各种依赖。外卖可以手写autolayout,电影可以用storyboard。外卖可以用mvc,电影可以mvvm。想怎么搞就怎么搞。他们两个就像独立的App一样。

有不少朋友包括我自己之前,认为做了前2步就是组件化了。只有真正做到了第3步,并且完善了相关架构,我才认为能称之为组件化。

那么我们来看看真正的组件化应该包含什么,什么情况适合组件化。业界内部的讨论已经有很多了,我来列举下我自己的看法。

画一个图:


default
default

适合的情况

  • 业务上要分治。
  • Team规模大,30人+。
  • 业务越来越多,越来越大。

如果不符合这些情况,我认为做组件化没有意义。因为性价比太低。

有一种情况表面上都符合上面列的条件,但实际上不适合组件化:例如我们公司。虽然有好几个iOS Team,虽然总人数上超过了30人,但每一个Team都只有6~10人。每个Team各自维护各自的一个App,各个App业务上没有交集,只公用1和2步的CocoaPods库。就算有交集,做相同的业务,也不打算公用或重用这部分代码(内部有竞争关系)。

我们公司这种情况就像是拆分成了好几个无关的小公司,大家都用了github上的一些CocoaPods库一样。

还好早期推了第1步和第2步,避免了每个Team之间都去造差不多功能的轮子,而能把精力尽量集中在各自的业务上,避免了一些资源浪费。

我认为需要包含什么(不分先后顺序)

  • App生命周期及事件如何下发给业务组件。
  • 业务组件之间没有依赖关系,需要解耦。
  • 解决组件化页面跳转的问题。
  • 解决业务组件之间通信的问题。
  • 解决如何划分抽象业务组件、基础功能组件(业务无关)和弱业务组件。
  • 统一的网络服务,本地存储方式等。
  • 去Model化。
  • 如何披露接口信息,调用方式,参数等等。
  • 明确组件的生命周期。
  • 提供二进制化方案。
  • 组件的subspec。
  • 版本规范。
  • 持续集成。
  • 代码准入制度。
  • 统一的命名规范。
  • 集成调试。
  • 代码维护。

所以我们得出的结论是:不轻易组件化。而是统筹规划好以上所有的内容。可以不用一步就位全部做好,但要预先想好每一步的解决方案;能够承上启下。

如果你要问我说哪一步比较重要,我觉得都挺重要的。要结合自己的实际情况,去排一个优先级。

App生命周期及事件如何下发给业务组件

例如:applicationDidEnterBackground,didRegisterUserNotificationSettings,didReceiveRemoteNotification等等。
通过注册方式,App向注册的业务组件中的协议发送消息。

业务组件之间没有依赖关系,需要解耦

通过依赖协议,或依赖下沉等方式解耦。准确拆分业务组件,弱业务组件,基础功能组件。保证单一原则、DRY 原则等。

解决组件化页面跳转的问题

各种router。比如MGJRouter
我不建议是淡出使用URL传参。理由是可以传参的对象受限制。

我们自己有一套叫GOTO的东西。使用分类。唯一的问题,你需要知道你要跳转页面的去model化参数是什么,代表该页面的枚举是什么,目前没法注册。

解决业务组件之间通信的问题

组件间需要相互调用,监听回调。不是说不能相互依赖么?对,可以通过依赖协议或中间件(依赖下沉)等方式解决这个问题。比如CTMediator。CTMediator应该是属于依赖下沉的方式。

解决如何划分抽象业务组件、基础功能组件(业务无关)和弱业务组件

这个得要从各自的实际情况出发。但有几个原则可以借鉴:

  • 重要性
  • 重用性
  • 单一性

统一的网络服务,本地存储方案等

可以通过创建弱业务Pod库解决这个问题。

为什么要这么做?
Team之间人员调动后可以快速入手。

去Model化

业务组件间通讯尽量去Model化。否则就得把该Model单独做成Pod库。

去Model化后,比如使用NSDictionary如何及时传播具体的参数信息?(文档?口口相传?写在头文件?)

如何披露接口信息、调用方式、参数和一些规则等等

文档?口口相传?写在头文件?使用协议?

各有利弊和适用场景。

按目前情况,我们选择写在头文件。

明确组件的生命周期。

明确组件的生命周期,就能在App中统一的创建,注册,集成,协作,销毁。

提供二进制化方案

二进制化方案能够提高编译速度,提升开发效率。集中注意力在自己维护的业务组件上。
二进制化方案

组件的subspec。

subspec教程。
使用subspec可以降低集成调试门槛。集中注意力在自己维护的业务组件上。让组件间依赖更清晰。

版本规范

可以参考semver

也可以参考我们的:
组件的依赖版本尽量宽泛一点,精确到minor就行。在App里精确到patch就可以了。然后大家只要按照规范发版本就可以了。参考一下这个规范

持续集成

主要工具可以有:gitlab runnerjenkinsfastlnefir.im

持续集成我们是这样做的。

CI工具是gitlab runner。每当一定条件下,会触发build IPA并且上传到fir.im

dev分支用的是dev证书。
master分支用的是adhoc证书。

测试人员可以通过http://fir.im/TestXXApphttp://fir.im/XXApp来分别下载。

.gitlab-ci.yml中的构建和上传看起来是这样的:

xcodebuild -exportArchive -archivePath 'build/p4.xcarchive' -exportPath 'build' -exportOptionsPlist exportOptionsDebug.plist | xcpretty

fir publish build/*.ipa -c $CI_BUILD_REF -T $FIR_TOKEN_DEBUG

在组件化开发中,一定条件应该是:

  • 业务组件发版更新(会自动修改App的Podfile,然后正常push。修改的部分不只是业务组件的版本号,业务组件可能需要更高版本的其他组件或第三方组件,它会在Podfile中一并修改这些库的版本号)
  • dev/master分支正常push
  • 手动触发

代码准入

Build/Test/Lint,code review,CI。

有了CI,就可以谈谈代码准入了。

  1. Build正常构建成功
  2. 单元测试通过(我们用的Kiwi
  3. Lint通过
  4. deploymate检查API
  5. OCLint检查代码
  6. CocoaPods Lint。不仅会Build一遍,还会检查podspec相关内容设置的对不对。如果没有用--allow-warnings的参数,有waring发生Lint是会不通过的。(建议把warning当作error,不要使用--allow-warings参数)
  7. Code Review。
    1. 检查发版规范。比如:我们更改了一个弱业务组件,升了一个patch版本号,但其实不只是修了bug,而且还增加了向前兼容的新功能,这个时候应该升的是minor版本号。
    2. 检查代码风格。
    3. 检查潜在的bug。
    4. 检查其他只有人能看得出的问题。

.gitlab-ci.yml中的OCLint和dploymate看起来是这样的:


Deploymate --cli -t jryMobile p4.xcworkspace -V 8.0 -x

xcodebuild -workspace p4.xcworkspace -scheme p4 -configuration Adhoc -archivePath 'build/p4' archive | tee xcodebuild.log | xcpretty

oclint-xcodebuild xcodebuild.log

oclint-json-compilation-database -e Pods -e Chart -e Chart/core/jsoncpp -e RKNotificationHub.m -e TTMessage.mm -e SSNetworkInfo.m -e Tween.mm -e 略...... && echo 'OCLint Passed' || (cat report.json && exit 1)

命名规范

公司名+组件名+具体名字

集成调试

各自业务组件如何调试?应该就和在主App中一样,只需要在Example App中依赖相关的其他业务组件即可。

另一种情况是,当业务组件版本更新时需要自动修改主App的Podfile中的版本,自上而下的触发集成。

代码维护

谁来维护基础功能组件和弱业务组件?如何保证某个Team提交代码后不会影响其他Team。(包含了:代码准入,集成调试,相互协作,版本规范)

需要一个Team专门来做这个事情。

补充:写在主App中的业务,要把自己当作业务组件,不能够依赖其他业务组件。

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

推荐阅读更多精彩内容