Jul
6
随着现在互联网工程无限扩大的趋势,每一个技术方向均在经历各种拆拆拆,模块化解耦的过程,当然客户端也不例外。客户端早在5年前就完成了组件化到模块化这一过程,各种模块化方法层出不穷并在各大项目中落地。然而模块化之后,大家前往配置化的路途上却是相当坎坷,相对于服务端方案,web前端方案来说确实拿不出手。在服务端spring风格的xml配置和注解配置让javaweb服务业务基础搭建效率大大提升,web配置甚至能让运营完成活动落地页的搭建而不关心基建部分,它们的配置化都是革新性的银弹技术方案。而客户端做配置化能成为银弹么?
配置化起源与根本诉求
客户端业界做配置化的起源其实从三个方向方向而来:一个是做模块化的那帮人,希望模块化能落入一个可以配置化的框里;另一个则是做脚手架的那帮人,希望脚手架能覆盖更持久的产研生命周期;还有一个是做移动端PaaS平台那帮人,希望能更低成本的扩展自己的产品。这三条路目前都汇到了客户端配置化上。
1. 模块化到配置化
模块化是从组件化演进而来,组件化当初解决的什么问题?基础代码和中间件和业务层解耦,基础代码提升复用率和代码质量。而模块化则进一步完成了各个中间件模块与上层的业务模块各自之间的拆分解耦合。比较理想的移动端组件化与模块化后:
a. 从下至上,基础模块层到中间件层到业务层,每层组件之间无耦合,通过通信中间件进行交互。
b. App壳工程中无业务代码,应用靠持续集成组合。
但是实际review目前的模块化方案后,目前还存在差距即App移动部分还是需要把各个层次的组件耦合在一起编排(即使不在壳工程里),并且组件无法做到按需引入(大量实际引入的组件都会对耦合代码进行入侵)因此也难以做到完整的可插拔。而如果做到了100%,实际就可以通过一个配置文件,来完成整个应用的组合而没有任何入侵,即进阶到配置化。
因此可见,这条路径上,配置化是模块化做到彻底的自然而然得到的结果,即生产代码与应用无耦合,生产代码之间也无耦合,单位生产代码独立可插拔;自然如果不是用代码将它们耦合在一起,就是通过配置将它们耦合在一起(本质依赖管理也是配置化的一部分)。
因此模块化配置化的根本诉求即模块化的理想:解耦。而组件/业务/领域上的100%解耦带来的效率提升,管理/质量保证成本的降低是显而易见的收益。
2. 脚手架配置化
脚手架也是移动端上古时代人人都在弄的东西。甚至谷歌官方也下手做了一个Jetpack(https://developer.android.com/jetpack/)作为脚手架支撑,结合Android Studio完成脚手架工作。上古开发者做脚手架的初衷是什么?
a. 快速搭建项目,通过几行命令或者一个配置文件就可以完成一个项目搭建。简单来说为项目搭建过程提效率。
b. 项目标准化,比如一个mvvm为基础的android项目,该引入哪些正确的包,第三库,标准页面的写法均可以通过脚手架一键生成。
c. 项目管理约束,脚手架也可以成为项目管理上的约束手段,通过项目标准化与工具化来保障项目的变更符合某种规则。
然而显然,以上三项的核心部分——项目到底会变成什么样子,具有非常主观的成分即包含了大量实际技术管理者的意志,因此每个脚手架都无法100%满足每个team的意志,每个脚手架都会有无数人提出无限的需求,或者世界上会存在无限的脚手架组合。因此实际上脚手架在使用上做约束的同时,自身能力上则大力发展覆盖范围与定制化,并走向配置化的道路。
同时,大家在使用脚手架的过程中也意识到脚手架目前的做法的局限性——它只能管控住项目/页面创建过程,而迭代过程却少有手段或者能力去做管控——如果我要管控一个应用的依赖库应该是什么样子,我当然也需要管控住迭代后可能增减的依赖库。因此大家的脚手架方案逐渐从纯线下工具类迭代为编译/构建时方案甚至运行时方案。
在定制化与管控范围扩大的两个方向加持下,脚手架自然往高度配置化的方向前进起来。并且配置化也完全符合目前看到的脚手架核心诉求:高度定制化的约束管控能力。
3. 移动端PaaS
为移动端提供在线服务的厂商远比web前端多。简单的web前端可能只需要一个在线统计服务就ok了,而移动端默认看下来一个正常的app除了统计功能,至少也需要性能采集,异常Crash监控,推送,安全(加壳)等在线服务,对于一些领域如im,音视频就更多了。因此业界做移动端在线服务的厂商相当多,并且使用也是相当广泛,我们将这些服务视为移动端PaaS。
一般来说一个PaaS服务最小需要提供一个sdk与一篇接入文档,一般来说介入的应用技术人员肯定是能看懂的,但是稍微复杂一些或者灵活性更高一些的服务,接入配置就会复杂很多常见的比如推送和地图服务类的SDK,线上和代码中的配置相当复杂。简而言之,稍复杂的接入成本自然会为PaaS服务带来推广与客服成本上的阻碍。SDK之所以无法完成自动化接入核心问题还是它是运行时的,这里反倒是有一个线下工具会更方便。
因此通过下线更自动化/可配置化的方式,完成PaaS服务在客户项目中的接入和维护——自然是各个PaaS服务商的目标。特别是针对提供的PaaS服务较多的厂商如友盟或者阿里云或者腾讯云,完成可以用一个工具来解决下属大量SDK的配置化接入与维护过程。
因此对于移动端PaaS服务,推进配置化工具的核心诉求是:降低服务接入与维护成本。这一点对于大公司内部的中间件团队来说也是一致的。
——————
以上三个方向的人都在做移动端配置化,它们自然走到了一起,因此目前业界对移动端配置化的展望包括了以上三部分的核心诉求即:a. 配置化完成彻底项目解耦组合。b. 配置化完成项目基础维护管控。c. 配置化降低依赖库与服务接入成本。
目前业界做得最好的应该是蚂蚁的mpaas(https://mpaas.com),它是在paas诉求和一部分脚手架诉求集合之下的产物,实际的配置化产物是一个ide插件与对应的配置文件,线上线下整合完成在ide中进行项目配置。然后其相对于完整诉求的缺陷是,自由度低:只覆盖了蚂蚁paas服务自己的组件,因此无法利用这套工具进行全覆盖管控;管控手段不足:如果是持续集成可用的工具就可以做构建管控了,现在只能做线下管控。
困难的根因
经过上面的讨论,我理解业界对移动端配置化的诉求基本上是有统一认知的。不过实际上这件事大家几乎都在打嘴炮或者没能做成,显然是有巨大的困难在其中。讨论这个话题也是笔者正在做相关的事情,目前梳理开困难是如此展开的:
1. 组件/依赖库覆盖过多并且繁杂导致工作量极大。web前端虽然说一直有新的技术方案层出不穷,但是在同一个时代,整个业界的主流技术方案其实是高度相似甚至趋同的,所以web前端脚手架与配置化方案相当好做。而对于移动端来说,本身开源业界大家使用的就乱七八糟的,Android整体相对还好因为谷歌推出的库能解决大部分问题,主要乱集中在功能性库上,iOS则基本上百花齐放,光就布局方案都是3大方向的库。因此就算配置化工具只是覆盖自己团队规范约束的依赖范围,也是相对于web前端大很多的量,如果考虑到把业界常用的库均纳入进去,必然需要众包的力量才又可能完成。
2. 移动端组件解耦方案百花齐放不统一,改动风险大。不像是js这种动态语言直接判断拆分打包解耦,无论是java还是oc或者swift,无代码依赖的解耦方案均是相当复杂的。因此我们做了一套100%配置化并且解耦的方案,相关配置化方案的解耦适配,每个组件都要来一套(这就是1所说的成本)并且每个组件的可适配难易度,适配可能带来的损失和风险均是不可预期的。如果js做配置化中间层就像一张纸一样粘在一起的话,移动端做配置化更像是把每个组件装箱嵌入机架中。更具体来说,是做启动时与运行时的组件交互适配,之前(https://lrdcq.com/me/read.php/120.htm)有讨论过。
3. 配置化收益存疑。在如上描述的这么大的成本后,朝着以上三个目标上收益到底有多大呢?
a. 对于解耦诉求来说,到目前这个程度继续做到100%解耦的收益其实相当少了。因为目前主要耦合的地方即App启动与App生命周期部分,就算巨型客户端相关代码也是万行以上的规模,一个人统一收口管理就好。同时App启动部分的变更频率相对于业务代码变更频率低太多(就像,我确实有一堆垃圾代码,但是进入维护阶段后那些代码每个月也就动50行,那我更倾向于保持现状),显然不会被视为成本大户。因此剩下的只有程序员对代码洁癖的追求而已了。
b. 对于脚手架的收益,争议就更大了。本身可能就存在50%左右的程序员认为脚手架没有意义——对于一个水平正常的程序员来说,通过自己的基础积累手动创建一个符合团队标准的项目种子的成本也就1一个小时以内,考虑到创建项目行为本身也是低频率行为,所以确实也可以不视为成本。剩下的就是管控诉求——管控的本质是通过执行管控的成本付出来带来在项目执行特别是线上质量,风险管理上的成本收益。然而这也是一个因人因团队而异的付出,对于过于大的团队,管控的执行成本会非常非常高;而对于小而美的团队,这个管控动作在质量上的收益确实不明确或者人工管控的成本远小于工具化管控。能想到的明显有收益的场景也就是外包导向的中型团队了。
c. 而配置化后对于移动端paas服务团队的收益,确实是相对明确的。但是paas服务团队没有诉求去做大而全的配置化框架,只包含自己提供的组件不就好了(像mpaas一样)。因此只是解决paas服务的成本问题得到的配置化方案,更像是某个厂商生态服务绑定的枷锁,自然而然不能成为某一个业界通用方案。
总体来看,移动端配置化确实可以是一颗银弹,但是并不是每个人都需要这么一颗完整的银弹而是只需要一部分就可以给团队查漏补缺,也就没人会期待一颗银弹了,也不会有人在这颗银弹上做投入。
各自替代方案与可能存在的展望
a. 抛弃Native的开发方式。从代码洁癖的角度来说,之所以客户端要做这么复杂的模块化,耦合成本高,核心因素还是native语言的限制——动态发布太困难了,包大小会成为业务瓶颈。因此脱离谷歌与苹果,业界在降低业务开发成本上实际上付出得最多的还是——动态化。具体来说,业务开发动态化,应用容器化。
自己观察mpaas的发展也会发现,21年开始,mpaas开始着重推销其提供的支付宝小程序框架。应该是他们注意到在与其在SDK的可配置性和可组合性上下功夫,还不如把壳应用固定下来而容器做好让更多的用户用起来,并加强容器本身的能力建设。这样相当于在native部分的灵活性稳定下来后改动风险也随业务开发转移而降低了。其他方案如搞ReactNative或者纯web容器也是同理。
换句话说,做动态化容器化的好处是,把原本native开发时,基础库的灵活性与风险固定了下来,并且还使得业务代码对native的调用通过容器API标准化了,因此直接实现了native成本降低与业务开发标准化。到这个程度也就不需要配置化去解决native问题了。同时考虑到动态化带来的其他收益,容器化与标准native容器方向是配置化以外绝佳的出路。
b. Native开发容器化(Framework标准化)。对于现在native开发在配置化上遇到的各种困难很大一个关系就是native开发的灵活性带来的。如果我们能做到:a. 技术选型相对固定化,比如在一个公司范围内所有团队应用的技术选型完全一致,比如mvvm模式的开发有大型开源项目通吃完整生命流程。b. 系统GUI框架切面化,即除了系统提供的生命周期,也能提供足够的切面或者配置方式让业务代码和组件代码非常标准的纳入应用生命周期中。这样一来,native开发也能和动态化容器开发那样能力标准并收敛,因此称为Native容器化。有了它就可以实现我们理想的native配置化。
这个方向实际做起来需要在现有的GUI方案上整体套一个解耦层,听起来是一个吃力不讨好的活,因此业界目前在跨端方案正火的这几年并没有太多精力投入native容器开发中。因此这一点需要预期谷歌与苹果在自身的技术方案发力后再去寻找突破口。
现在反倒是插件化(iOS对应动态库)方案虽然是少数人的玩具,但是在按需拆解,加载,解耦代码冷启动方面有一定技术优势,说不定也能进化为另一条native容器化开发的路子。
配置化起源与根本诉求
客户端业界做配置化的起源其实从三个方向方向而来:一个是做模块化的那帮人,希望模块化能落入一个可以配置化的框里;另一个则是做脚手架的那帮人,希望脚手架能覆盖更持久的产研生命周期;还有一个是做移动端PaaS平台那帮人,希望能更低成本的扩展自己的产品。这三条路目前都汇到了客户端配置化上。
1. 模块化到配置化
模块化是从组件化演进而来,组件化当初解决的什么问题?基础代码和中间件和业务层解耦,基础代码提升复用率和代码质量。而模块化则进一步完成了各个中间件模块与上层的业务模块各自之间的拆分解耦合。比较理想的移动端组件化与模块化后:
a. 从下至上,基础模块层到中间件层到业务层,每层组件之间无耦合,通过通信中间件进行交互。
b. App壳工程中无业务代码,应用靠持续集成组合。
但是实际review目前的模块化方案后,目前还存在差距即App移动部分还是需要把各个层次的组件耦合在一起编排(即使不在壳工程里),并且组件无法做到按需引入(大量实际引入的组件都会对耦合代码进行入侵)因此也难以做到完整的可插拔。而如果做到了100%,实际就可以通过一个配置文件,来完成整个应用的组合而没有任何入侵,即进阶到配置化。
因此可见,这条路径上,配置化是模块化做到彻底的自然而然得到的结果,即生产代码与应用无耦合,生产代码之间也无耦合,单位生产代码独立可插拔;自然如果不是用代码将它们耦合在一起,就是通过配置将它们耦合在一起(本质依赖管理也是配置化的一部分)。
因此模块化配置化的根本诉求即模块化的理想:解耦。而组件/业务/领域上的100%解耦带来的效率提升,管理/质量保证成本的降低是显而易见的收益。
2. 脚手架配置化
脚手架也是移动端上古时代人人都在弄的东西。甚至谷歌官方也下手做了一个Jetpack(https://developer.android.com/jetpack/)作为脚手架支撑,结合Android Studio完成脚手架工作。上古开发者做脚手架的初衷是什么?
a. 快速搭建项目,通过几行命令或者一个配置文件就可以完成一个项目搭建。简单来说为项目搭建过程提效率。
b. 项目标准化,比如一个mvvm为基础的android项目,该引入哪些正确的包,第三库,标准页面的写法均可以通过脚手架一键生成。
c. 项目管理约束,脚手架也可以成为项目管理上的约束手段,通过项目标准化与工具化来保障项目的变更符合某种规则。
然而显然,以上三项的核心部分——项目到底会变成什么样子,具有非常主观的成分即包含了大量实际技术管理者的意志,因此每个脚手架都无法100%满足每个team的意志,每个脚手架都会有无数人提出无限的需求,或者世界上会存在无限的脚手架组合。因此实际上脚手架在使用上做约束的同时,自身能力上则大力发展覆盖范围与定制化,并走向配置化的道路。
同时,大家在使用脚手架的过程中也意识到脚手架目前的做法的局限性——它只能管控住项目/页面创建过程,而迭代过程却少有手段或者能力去做管控——如果我要管控一个应用的依赖库应该是什么样子,我当然也需要管控住迭代后可能增减的依赖库。因此大家的脚手架方案逐渐从纯线下工具类迭代为编译/构建时方案甚至运行时方案。
在定制化与管控范围扩大的两个方向加持下,脚手架自然往高度配置化的方向前进起来。并且配置化也完全符合目前看到的脚手架核心诉求:高度定制化的约束管控能力。
3. 移动端PaaS
为移动端提供在线服务的厂商远比web前端多。简单的web前端可能只需要一个在线统计服务就ok了,而移动端默认看下来一个正常的app除了统计功能,至少也需要性能采集,异常Crash监控,推送,安全(加壳)等在线服务,对于一些领域如im,音视频就更多了。因此业界做移动端在线服务的厂商相当多,并且使用也是相当广泛,我们将这些服务视为移动端PaaS。
一般来说一个PaaS服务最小需要提供一个sdk与一篇接入文档,一般来说介入的应用技术人员肯定是能看懂的,但是稍微复杂一些或者灵活性更高一些的服务,接入配置就会复杂很多常见的比如推送和地图服务类的SDK,线上和代码中的配置相当复杂。简而言之,稍复杂的接入成本自然会为PaaS服务带来推广与客服成本上的阻碍。SDK之所以无法完成自动化接入核心问题还是它是运行时的,这里反倒是有一个线下工具会更方便。
因此通过下线更自动化/可配置化的方式,完成PaaS服务在客户项目中的接入和维护——自然是各个PaaS服务商的目标。特别是针对提供的PaaS服务较多的厂商如友盟或者阿里云或者腾讯云,完成可以用一个工具来解决下属大量SDK的配置化接入与维护过程。
因此对于移动端PaaS服务,推进配置化工具的核心诉求是:降低服务接入与维护成本。这一点对于大公司内部的中间件团队来说也是一致的。
——————
以上三个方向的人都在做移动端配置化,它们自然走到了一起,因此目前业界对移动端配置化的展望包括了以上三部分的核心诉求即:a. 配置化完成彻底项目解耦组合。b. 配置化完成项目基础维护管控。c. 配置化降低依赖库与服务接入成本。
目前业界做得最好的应该是蚂蚁的mpaas(https://mpaas.com),它是在paas诉求和一部分脚手架诉求集合之下的产物,实际的配置化产物是一个ide插件与对应的配置文件,线上线下整合完成在ide中进行项目配置。然后其相对于完整诉求的缺陷是,自由度低:只覆盖了蚂蚁paas服务自己的组件,因此无法利用这套工具进行全覆盖管控;管控手段不足:如果是持续集成可用的工具就可以做构建管控了,现在只能做线下管控。
困难的根因
经过上面的讨论,我理解业界对移动端配置化的诉求基本上是有统一认知的。不过实际上这件事大家几乎都在打嘴炮或者没能做成,显然是有巨大的困难在其中。讨论这个话题也是笔者正在做相关的事情,目前梳理开困难是如此展开的:
1. 组件/依赖库覆盖过多并且繁杂导致工作量极大。web前端虽然说一直有新的技术方案层出不穷,但是在同一个时代,整个业界的主流技术方案其实是高度相似甚至趋同的,所以web前端脚手架与配置化方案相当好做。而对于移动端来说,本身开源业界大家使用的就乱七八糟的,Android整体相对还好因为谷歌推出的库能解决大部分问题,主要乱集中在功能性库上,iOS则基本上百花齐放,光就布局方案都是3大方向的库。因此就算配置化工具只是覆盖自己团队规范约束的依赖范围,也是相对于web前端大很多的量,如果考虑到把业界常用的库均纳入进去,必然需要众包的力量才又可能完成。
2. 移动端组件解耦方案百花齐放不统一,改动风险大。不像是js这种动态语言直接判断拆分打包解耦,无论是java还是oc或者swift,无代码依赖的解耦方案均是相当复杂的。因此我们做了一套100%配置化并且解耦的方案,相关配置化方案的解耦适配,每个组件都要来一套(这就是1所说的成本)并且每个组件的可适配难易度,适配可能带来的损失和风险均是不可预期的。如果js做配置化中间层就像一张纸一样粘在一起的话,移动端做配置化更像是把每个组件装箱嵌入机架中。更具体来说,是做启动时与运行时的组件交互适配,之前(https://lrdcq.com/me/read.php/120.htm)有讨论过。
3. 配置化收益存疑。在如上描述的这么大的成本后,朝着以上三个目标上收益到底有多大呢?
a. 对于解耦诉求来说,到目前这个程度继续做到100%解耦的收益其实相当少了。因为目前主要耦合的地方即App启动与App生命周期部分,就算巨型客户端相关代码也是万行以上的规模,一个人统一收口管理就好。同时App启动部分的变更频率相对于业务代码变更频率低太多(就像,我确实有一堆垃圾代码,但是进入维护阶段后那些代码每个月也就动50行,那我更倾向于保持现状),显然不会被视为成本大户。因此剩下的只有程序员对代码洁癖的追求而已了。
b. 对于脚手架的收益,争议就更大了。本身可能就存在50%左右的程序员认为脚手架没有意义——对于一个水平正常的程序员来说,通过自己的基础积累手动创建一个符合团队标准的项目种子的成本也就1一个小时以内,考虑到创建项目行为本身也是低频率行为,所以确实也可以不视为成本。剩下的就是管控诉求——管控的本质是通过执行管控的成本付出来带来在项目执行特别是线上质量,风险管理上的成本收益。然而这也是一个因人因团队而异的付出,对于过于大的团队,管控的执行成本会非常非常高;而对于小而美的团队,这个管控动作在质量上的收益确实不明确或者人工管控的成本远小于工具化管控。能想到的明显有收益的场景也就是外包导向的中型团队了。
c. 而配置化后对于移动端paas服务团队的收益,确实是相对明确的。但是paas服务团队没有诉求去做大而全的配置化框架,只包含自己提供的组件不就好了(像mpaas一样)。因此只是解决paas服务的成本问题得到的配置化方案,更像是某个厂商生态服务绑定的枷锁,自然而然不能成为某一个业界通用方案。
总体来看,移动端配置化确实可以是一颗银弹,但是并不是每个人都需要这么一颗完整的银弹而是只需要一部分就可以给团队查漏补缺,也就没人会期待一颗银弹了,也不会有人在这颗银弹上做投入。
各自替代方案与可能存在的展望
a. 抛弃Native的开发方式。从代码洁癖的角度来说,之所以客户端要做这么复杂的模块化,耦合成本高,核心因素还是native语言的限制——动态发布太困难了,包大小会成为业务瓶颈。因此脱离谷歌与苹果,业界在降低业务开发成本上实际上付出得最多的还是——动态化。具体来说,业务开发动态化,应用容器化。
自己观察mpaas的发展也会发现,21年开始,mpaas开始着重推销其提供的支付宝小程序框架。应该是他们注意到在与其在SDK的可配置性和可组合性上下功夫,还不如把壳应用固定下来而容器做好让更多的用户用起来,并加强容器本身的能力建设。这样相当于在native部分的灵活性稳定下来后改动风险也随业务开发转移而降低了。其他方案如搞ReactNative或者纯web容器也是同理。
换句话说,做动态化容器化的好处是,把原本native开发时,基础库的灵活性与风险固定了下来,并且还使得业务代码对native的调用通过容器API标准化了,因此直接实现了native成本降低与业务开发标准化。到这个程度也就不需要配置化去解决native问题了。同时考虑到动态化带来的其他收益,容器化与标准native容器方向是配置化以外绝佳的出路。
b. Native开发容器化(Framework标准化)。对于现在native开发在配置化上遇到的各种困难很大一个关系就是native开发的灵活性带来的。如果我们能做到:a. 技术选型相对固定化,比如在一个公司范围内所有团队应用的技术选型完全一致,比如mvvm模式的开发有大型开源项目通吃完整生命流程。b. 系统GUI框架切面化,即除了系统提供的生命周期,也能提供足够的切面或者配置方式让业务代码和组件代码非常标准的纳入应用生命周期中。这样一来,native开发也能和动态化容器开发那样能力标准并收敛,因此称为Native容器化。有了它就可以实现我们理想的native配置化。
这个方向实际做起来需要在现有的GUI方案上整体套一个解耦层,听起来是一个吃力不讨好的活,因此业界目前在跨端方案正火的这几年并没有太多精力投入native容器开发中。因此这一点需要预期谷歌与苹果在自身的技术方案发力后再去寻找突破口。
现在反倒是插件化(iOS对应动态库)方案虽然是少数人的玩具,但是在按需拆解,加载,解耦代码冷启动方面有一定技术优势,说不定也能进化为另一条native容器化开发的路子。