一、代码中心化问题
将一个大型的项目拆分成多个Module或者新开的组件化项目,想要的预期是这些module之间是平级的关系.这样一来就可以使得业务相对集中,每个人都可以专注在一件事上。同时,代码的耦合度也会随之降低,达到高度解耦状态,因为同级的module不存在依赖关系,在编译上就是隔离的,这会让组件间的依赖非常清楚,同时也具有更高的重用性,组件强调复用,模块强调职责划分。 他们没有非常严格的划分。
达到可复用要求的模块,那么这个模块就是组件。每个组件的可替代性、热插拔、独立编译都将可行,
1.1 代码中心化在Android组件化中的问题体现
貌似Android的组件化是非常简单且可行的,AS提供的module创建方式加gradle.properies 自定义属性可读,或者ext全局可配置的project属性亦或kotlin dsl 中kotlin的语法糖都为我们提供了application和library的切换。
然后将代码放在不同的仓库位置最好是单独git 仓库级别的管理隔离,就能达到我们想要解决的一系列问题。
然而事情并不是想象的那么简单...
一些列的问题接踵而至,于我而言影响最深的就是应用设计时使用映射型数据库,导致集成模式和组件模式中复用出现问题;最终使用注解配合Java特性生成代码,虽然不完美但是依然解决了此问题。正当我为了胜利欢呼的时刻,一片《微信Android模块化架构重构实践》文章进入我的眼帘。
随即闪现出了一个重要且紧急的问题,代码中心化的问题
这个问题是怎么出现的呢?在微信Android模块化架构重构实践中是这样描述的
"""
然而随着代码继续膨胀,一些问题开始突显出来。首先出问题的是基础工程libnetscene和libplugin。基础工程一直处于不断膨胀的状态,同时主工程也在不断变大。同时基础工程存在中心化问题,许多业务Storage类被附着在一个核心类上面,久而久之这个类已经没法看了。此外当初为了平滑切换到gradle避免结构变化太大以及太多module,我们将所有工程都对接到一个module上。缺少了编译上的隔离,模块间的代码边界出现一些劣化。虽然紧接着开发了工具来限制模块间的错误依赖,但这段时间里的影响已经产生。在上面各种问题之下,许多模块已经称不上“独立”了。所以当我们重新审视代码架构时,以前良好模块化的架构设计已经逐渐变了样。
"""
再看他们分析问题的原因:
"""
翻开基础工程的代码,我们看到除了符合设计初衷的存储、网络等支持组件外,还有相当多的业务相关代码。这些代码是膨胀的来源。但代码怎么来的,非要放这?
一切不合理皆有背后的逻辑。在之前的架构中,我们大量适用Event事件总线作为模块间通信的方式,也基本是唯一的方式。使用Event作为通信的媒介,自然要有定义它的地方,好让模块之间都能知道Event结构是怎样的。这时候基础工程好像就成了存放Event的唯一选择——Event定义被放在基础工程中;接着,遇到某个模块A想使用模块B的数据结构类,怎么办?把类下沉到基础工程;遇到模块A想用模块B的某个接口返回个数据,Event好像不太适合?那就把代码下沉到基础工程吧……
就这样越来越多的代码很“自然的”被下沉到基础工程中。
我们再看看主工程,它膨胀的原因不一样。分析一下基本能确定的是,首先作为主干业务一直还有需求在开发,膨胀在所难免,缺少适当的内部重构但暂时不是问题的核心。另一部分原因,则是因为模块的生命周期设计好像已经不满足使用需要。之前的模块生命周期是从“Account初始化”到“Account已注销”,所以可以看出在这时机之外肯定还有逻辑。放在以前这不是个大问题,刚启动还不等“Account初始化”就要执行的逻辑哪有那么多。而现在不一样,再简单的逻辑堆积起来也会变复杂。此时,在模块生命周期外的逻辑基本上只能放主工程。
此外的问题,模块边界破坏、基础工程中心化,都是代码持续劣化的帮凶...