F2533d0b2ea569dac881cbcdf88401aa
悦跑圈Android单业务开发,提高编译效率15倍

关于标题

“15倍”是怎么算出来的呐?

配置:
Mac mini,双核 Intel Core i5 2.6GHz,8G内存,SSD(自行更换)

性能:

全量编译application平均需要5分钟,单业务application编译运行,平均仅需7~20秒. (300s/20s = 15)

(如果你用相同配置windows系统,基本是编译不过去的,至少要i7。)

什么是单业务编译

如果读者你看过笔者写的《App组件化与业务拆分那些事》《Android使用Provider做业务数据交互》,就能了解如何对工程划分业务了,此处不累赘。

那两篇文章,是为本文做铺垫。前两篇讲了开发思路、理念方面,说了那么多优点,貌似也没什么实质数据支撑。那么,本文让你见识一下分业务开发的力量。

常见的开发模式,是一个工程,一个application、多个module或无module。

单application,多module

单application,多module

这种模式不足够支撑日益庞大的工程。于是,我们提出:

一个工程,多个application、多个module。

多application,多module

多application,多module

(由于排版问题,此图省略了Base Library)

Main Application跟“单application”时的Application一样,就是我们打包的application. 那么,application A、application B...又是什么呢?

从图里面看出,Application A只依赖Module A,Application B只依赖Module B....每个application可独立编译、运行。

独立编译业务优势

1.编译快、单元测试快
2.简化调试流程
3.更专注业务
4.可嵌入不需要在Main Application执行的代码
5.隔离不必要的业务和组件

1.编译快

正如前文提到,悦跑圈从全量编译平均5分钟,降到单业务编译7~20秒。就这么一个优势,就有充足的理由让我们从单application改造成多application

单元测试快

说说单元测试吧,很多同学都冲着“单元测试快速反馈结果、能提高开发效率”。然而,自身工程臃肿不堪,跑一个单元测试gradle会全工程扫描(部分或全量编译),时间上压根谈不上快(尽管比运行app再手动debug要好很多),有error还报错。这种情况还是挺常见的,例如你在重构代码,改几个业务,必须所有业务代码都写好(至少没有error),才能跑单元测试。

当项目按业务分成若干module,跑单元测试时,gradle仅扫描该业务module,即使其他module有报错,也不影响本次单元测试。而且因为编译代码量少,单元测试就能跑快了。

我们目前跑一个junit单元测试,算上编译和运行时间,仅需几秒。如果用robolectric跑DAO测试,就比较慢了,这个跟robolectric框架机制有关。

2.简化调试流程

业务比较多的APP,不一定每个功能的入口都很明显,有可能依赖其他功能流程。单业务application运行很好地解决了这个问题。

例如,你要调试“查看某用户勋章”,那么你必须先进入该用户界面,再点击“他的勋章”,才能进入“勋章墙”界面。你要找到用户名叫“键盘男”(uid=4)的用户,必须先去“发现用户”界面,输入“键盘男”或“4”,点击搜索,从搜索结果列表,找到想要找的“键盘男”用户,再点进去......光想想就觉得蛋疼,更别说做代码调试。

发现用户 -> 搜索“键盘男” -> 进入用户详情界面 -> 进入uid=4勋章墙

全流程

全流程

由于单业务application不会编译进Main application,因此我们在单业务application做什么都可以。于是,我们可以在“勋章application”写一个页面,有个Button和EditText,EditText输入uid,点Button直接进入该uid的勋章墙界面。是不是很简单?

EditText输入4 -> 进入uid=4勋章墙

单业务流程

单业务流程

同学们回忆一下,自己是不是把很多调试时间浪费在繁琐的流程上?

3.更专注业务

这个话题在笔者前两篇文章提及很多次了。一个业务一个module,能让你更清晰地管理业务代码和资源;现在,一个业务一个application,能让你更清晰地梳理业务流程,单业务application仅依赖当前业务module,让开发人员隔离无关业务代码。

对于经验尚浅的同学,这点可能稍微难理解。说实话,“专注业务”听起来比较虚,但恰恰能无形地让程序员提高开发效率。

例如,单业务开发把业务之间代码隔离,一来不会让你的业务代码干扰其他开发人员,二来其他业务代码也不会干扰你的代码

再举个反例,如果你在业务A写了ImageUtils.getSize(),其实这个ImageUtils跟业务A相关,例如根据dpi获取A界面某图片显示大小;在没有分业务开发情况下,业务B也调用你的ImageUtils.getSize(),当业务A修改ImageUtils.getSize(),业务B就有bug了.....如果是分业务开发,业务A下的ImageUtils(应该命名为AImageUtils)不可能被业务B调用,那么开发业务B的同学,只能乖乖地自己写一个BImageUtils.getSize()

CodeReview时,审核人要review业务A代码,他只需要看A module下的代码即可,不需要关心其他module代码,那么review速度和质量,自然有所提高。

这些情况,在平常开发中经常碰到,分业务开发可以很大程度上避免上述低级错误。归根到底,分业务就是高内聚,低耦合的编程理念:单业务高内聚,业务之间低耦合。

4.可嵌入不需要在Main Application执行的代码

这主要针对调试时修改数据的场景。例如,调试“无本地缓存,重新请求数据”场景,如果每次调试都要清空整个app数据,很麻烦,而且可能引起流程上的问题。

单业务application为这种场景提供了解决方案:在单业务application某Activity,点击某个Button,执行清空某数据的代码。

调试场景:
1.断网 -> 勋章墙 -> 显示缓存勋章
2.断网 -> 清空勋章数据 -> 无勋章,并显示默认图

清空缓存

清空缓存

如果没有单业务application,怎么做?很可能在某个界面,写一个Button,点击清空数据勋章缓存。但这里有问题,Button是写在勋章业务module,Main Application会依赖,在打包时需要去掉这部分代码,或者加if(BuildConfig.DEBUG)等条件。笔者非常不支持这种会影响Main application的做法,有可能因为这个改动,引起不必要的bug。

单业务application还能实现很多场景,希望同学们能自己去发掘!

5.隔离不必要的业务和组件

在本文“3.更专注业务”已经探讨了“隔离业务”,这里继续补充一下更多场景。

隔离其他业务数据

悦跑圈Android 勋章业务 需要获取 跑步业务 中个人跑量数据。按常理,为了实现这个需求,勋章业务 要依赖 跑步业务。我们的《Android使用Provider做业务数据交互》方案,正好解决依赖问题。

使用Provider可以让勋章业务不需要依赖跑步业务,但问题来了,个人跑量数据谁提供?在单业务application中,我们可以声明一个MockRunProvider,跟跑步业务RunProvider实现同样的RunProtocol接口,并保持authority一致;或者修改服务中心路由配置,让原来指向RunProviderrun authority,改成指向MockRunProvidermock authority。当然,MockRunProvider返回的数据不是真实的,是写死的。

由于编译运行单业务application很快,你可以快速地修改MockRunProvider数据来调试,这让开发人员省去很多不必要的流程。例如,需求当跑量大于1000KM显示文案X:正常开发流程,服务器上必须有某用户信息跑量大于1000KM,跑步业务请求回本地,再调用RunProvider才返回个人跑量,又或者在debug模式动态修改变量;而单业务application+MockRunProvider只需要写死跑量1000+KM就可以走后面的流程了,根本不需要关心服务器数据和请求数据,也不需要debug模式修改数据,开发人员只需要关心勋章业务如何实现即可!

top Created with Sketch.