随着 App 功能规模、团队规模不断扩大, 这时候可能需要层业务模块角度关注架构设计,目的是降低功能规模增加而带来的复杂度爆炸增长,横向架构强调的是业务模块之间的横向解耦,从而降低复杂度。
1、复杂度的评估
图中4个模块都存在着依赖关系, 那么复杂度计算为 24:复杂度=4x3x2x1
如果我们通过某种手段进行解耦(例如通过增加一个 api 服务层隔离):
通过这样解耦,复杂度变为了 5:四个模块加一个隔离层。
通过上面的分析,基本可以看到, 模块化解耦是一个 App 发展到一定规模后绕不开的话题, 淘宝、微信等这样的巨型 App 早已在迭代过程中进行了多轮的模块化重构, 参考:《微信 Android 模块化架构重构实践
https://cloud.tencent.com/developer/article/1005631》
检验标准:横向架构是否成功, 检验的标准是,如果这个模块给独立小组开发,是否可以独立开发、编译、调试。
2、架构不是一套打遍天下
我经历过几十万、几百万的中小型 App 搭建, 也参与千万日活的大型 App 应用架构,后者的架构更复杂,用到的技术和手段也更丰富,是不是就可以把后者套用上去呢?答案显然是否定的,不可能说微信的架构很牛, 那我们就搬过来用。架构设计需要满足三原则:
详细可以参考:
《架构设计三原则https://time.geekbang.org/column/article/7071》
适合原则:根据当前的业务类型、规模选择合适的纵向、横向架构设计方案
简单原则:所有在做架构时,在有复杂方案和简单方案都可以满足当前业务是,尽量选择简单方案 。
演化原则:微信、淘宝这样的巨型 App,也不是一开始就设计成这样的架构的,很多 App 开始的时候可能都没有出现模块化、插件化这样的横向架构设计,都是随着功能和用户规模不断扩展,架构不断重构演化而来的。首先,设计出一个满足现有业务的架构,架构要在实际应用中不断的优化,保留其优秀的部分,修改有缺陷的设计、改正错误的设计、去掉无用的设计,使得架构不断完善。当业务发展时,旧的架构可以要重构、甚至重写,但是有价值的经验、教训却会在新的架构中体现。
3、先有架构再有设计模式
初入这个行业的时候, 很多设计模式是看得云里雾里, 我觉得是我们搞反了顺序,导致我们很难理解为什么用这个模式、 SOLID 设计原则有什么作用。
应该是先有业务场景, 然后再有什么样的架构, 为了到达这个架构的要求, 然后才是各种设计模式和设计原则的灵活选取和应用。
例如,我们为了让用户模块和消息模块解耦,假设用户模块依赖消息模块的未读消息数这个信息。
为了满足横向架构的要求,解除模块依赖,架构变成:
通过这样调整,我们不知不觉中使用了 SOLID 中的好几个原则,例如依赖倒置原则。
4、跨平台和动态性
跨平台和动态性是做 App 架构绕不开的一个话题。
两类跨平台:第一:UI 跨平台,代表方案 WebView、Weex、RN、Flutter 等类 web 方案。
第二:C++ 跨平台, 通常是在追求性能的某些特定场景, 例如音视频编解码处理,某些复杂的加解密算法等。也有一些团队由于领导班子技术栈的优势, 会选择将业务甚至 UI 也是用 C++ 跨平台,例如腾讯会议。
动态性:代表方案 WebView,Weex ,小程序等类 web 方案和原生插件化方案。
关于怎么选取,我们要完美的动态性或者跨平台性的时候,可能就是牺牲了某些性能,例如 WebView ,在跨平台性和动态性都堪称完美,但却是可选方案中性能最差的,再比如:如果我们使用 C++ ,性能上肯定没问题,但是在开发效率、团队人员技术要求上都要面临巨大挑战。
还有些选择是由业务本身决定的,例如类似应用宝这样的应用商店应用,根本就不用考虑跨平台问题, 因为它只能跑在 Android 平台, 但是它对动态性要求非常高,作为厂商的竞争对象无法在厂商应用商店上架,所以类似插件化这样的动态方案就显得非常重要。
架构中对于动态性和跨平台方案的选取,这同样是一个取舍问题, 架构干的活,大多数时候都是在做取舍和平衡。