本文已授权微信公众号 AndroidDeveloper 独家发布。
入职安居客三年从工程师到 Team Leader,见证了 Android 团队一路走来的发展历程。因此有心将这些记录下来与大家分享,也算是对自己三年来一部分工作的总结。希望对大家有所帮助,更希望能得到大家宝贵的建议。
三年前入职时安居客在业务上刚完成了三网合并(新房、二手房、好租和商业地产多个平台多个网站合成现在的 anjuke.com,这在公司的历史上称之为三网合并),因此移动端也将原先的新房、二手房、好租和商业地产多个 App 合并成为了现在的安居客 App。所谓的合并也差不多就是将多个项目的代码拷贝到了一起组成了新的 Anjuke Project。下面这张图能更加直观的呈现当时的状况:
这一时期代码结构混乱、层次不清,各业务技术方案不统一,冗余代码充斥项目的各个角落;甚至连基本的包结构也是胡乱不堪,项目架构更是无从谈起。大家只不过是不停地往上堆砌代码添加新功能罢了。于是我进入公司的第一件事就是向 Leader 申请梳理了整个项目的结构。
而后随着项目的迭代,我们不断引入了 Retrofit、UniversalImageLoader、OKHttp、ButterKnife 等一系列成熟的开源库,同时我们也开发了自己的 UI 组件库 UIComponent、基础工具库 CommonUtils、基于第三方地图封装的 MapSDK、即时聊天模块 ChatLibrary 等等。这之后安居客项目架构大致演变成了由基础组件层、业务组件层和业务层组成的三层架构。如下图:
其中业务层是一种非标准的 MVC 架构,Activity 和 Fragment 承担了 View 和 Controller 的职责:
前面这种分层的架构本身是没太大问题的,即使到了现在我们的业务项目也已然是基于这种分层的架构来构建的,只不过在不断的迭代中我们做了些许调整(分层架构后面在介绍组件化和模块化的时候会详细介绍)。但是随着业务的不断迭代,我们慢慢发现业务层这种非标准的MVC架构带来了种种影响团队开发效率的问题:
鉴于三网合并时期我还未加入安居客,所以对这一块的理解难免有偏差,如果有安居客的老同事发现文章中的描述有不对的地方还望批评指正。
一种技术架构无法满足所有的业务项目,更不可能有一种架构方案能够一劳永逸。正如上一节中提到的随着业务的不断迭代,现有架构的缺陷逐渐浮出水面,项目架构必需不断升级迭代才能更好地服务于业务。
在研究了 Google 推出的基于 MVP 架构的 Demo 后,我们发现 MVP 架构能解决现在所面临过的很多问题,于是我们学习并引入到了我们的项目中来,并针对性的做了部分调整。下图呈现的是安居客 MVP 方案:
以前面提到的三层架构的方案来看是这样的:
基于此架构我在 GitHub 上开源了一个项目MinimalistWeather,有兴趣的小伙伴可以去 Clone 下来看看,如果觉得对你有帮助就给个 Star 吧。 :)
另外这套MVP架构还为我们带来了一个额外的好处:我们有了足够明确的开发规范和标准。细致到了每一个类应该放到哪个包下,哪个类具体应该负责什么职责等等。这对于我们的 Code Review、接手他人的功能模块等都提供了极大的便利。前面提到的 MinimalistWeather 就是为了定规范定标准而开发的。
这一时期我们还在项目中引入了 RxJava,很好的解决了前面提到的嵌套回调的问题,同时能够帮助我们简化复杂业务场景下的代码逻辑(当然 RxJava 的好处远远不止这么一点,对 RxJava 不了解的同学可以去翻翻我之前一系列关于 RxJava 的文章)。我们也将网络库升级到了 Retrofit2 + OKHttp3,它们和 RxJava 之间能更好的配合。
是不是升级到了 MVP 架构就高枕无忧了呢?很明显不是这样!MVP 架构也会带来以下新的问题:
去年下半年我们 Android 团队内部成立了技术小组,基础组件的开发是技术小组很重要的一部分工作,所以组件化是我们正在做的事;模块化更多的是现有的方案受到来自业务上的挑战以及受到了 Oasis Feng 在 MDCC 上的分享和整个大环境的启发,现在正处于设计规划和 Demo 开发的阶段。
组件化不是个新概念,通俗的讲组件化就是基于可重用的目的,将一个大的软件系统拆分成一个个独立组件。
组件化的带来的好处不言而喻:
现在的安居客有是三个业务团队:安居客用户 App、经纪人 App、集客家 App。为了避免各个业务团队重复造轮子,团队中也需要有一定的技术沉淀,因此组件化是必须的。从本篇的第一节大家就能看到组件化的影子,只不过在这之前我们做的并不好。现在我们需要提供更多的、职能单一、性能更优的组件供业务团队使用。根据业务相关性,我们将这些组件分为:基础组件和业务组件。后面在介绍模块化的时候会有进一步的描述。
自从 Oasis Feng 在去年的 MDCC2016 上分享了模块化的经验后,模块化在 Android 社区越来越多的被提起。我们自然也不落俗的去做了一些研究和探索。安居客现在面临很多问题:例如全量编译时间太长(我这台13款的 MacBook Pro 上打一次包得花十多分钟);例如新房、二手房、租房等等模块间耦合严重,不利于多团队并行开发测试;另外在17年初公司重新将租房 App 捡起推广,单独让人来开发维护一个三年前的项目并不划算,所以我们希望能直接从现在的安居客用户端中拆分出租房模块作为一个单独的 App 发布上线。这样看来模块化似乎是一个不错的选择。
所以我们做模块化的目的大致是这样的:
15年 Trinea 还在安居客的时候开发了一套插件化框架,但受限于当时的团队规模并且插件化对整个项目的改造太大,因此在安居客团队中插件化并未实施下来。而模块化其实是个很好的过渡方案,将项目按照模块拆分后各业务模块间解耦的问题不存在了,后续如有必要,再进行插件化改造只不过是水到渠成的事。
整个项目分为三层,从下往上分别是:
同时针对模块化我们也需要定义一些自己的游戏规则:
对于模块化项目,每个单独的 Business Module 都可以单独编译成 APK。在开发阶段需要单独打包编译,项目发布的时候又需要它作为项目的一个 Module 来整体编译打包。简单的说就是开发时是 Application,发布时是 Library。因此需要你在 Business Module 的 Gradle 配置文件中加入如下代码:
if(isBuildModule.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
如果我们需要把租房模块打包成一个单独的租房 App,像下面这样就好:
我们可以把 Basic Component Layer 和 Business Component Layer 放在一起看做是 Anjuke SDK,新的业务或者项目只需要依赖 Anjuke SDK 就好(这一点同样是受到了 Trinea 文章的启发)。甚至我们可以做得更极致一些,开发一套自己的组件管理平台,业务方可以根据自己的需求选择自己需要的组件,定制业务专属的 Anjuke SDK。业务端和 Anjuke SDK 的关系如下图所示:
模块化拆分对于安居客这种比较大型的商业项目而言,由于历史比较久远很多代码都运行五六年了;各个业务相互交叉耦合严重,所以实施起来还是有很大难度的。过程中难免会有预料不到的坑,这就需要我们对各个业务有较深的理解同时也要足够的耐心和细致。虽然辛苦,但是一旦完成模块化拆分对整个团队及公司业务上的帮助是很大的。
以上是我的简单总结以及对模块化的一些思考,不足之处还望大家批评指正。后面模块化的 Demo 完善后我会把它放到 GitHub,并再出一篇文章详细介绍模块化的设计实现细节。
参考资料:
如果你喜欢我的文章,就关注下我的知乎专栏或者在 GitHub 上添个 Star 吧!
- 知乎专栏:https://zhuanlan.zhihu.com/baron
- GitHub:https://github.com/BaronZ88