安卓 fragment内显示网站_Coupang 安卓架构?—?Part 3 通过重构包消除依赖

在上一篇文章中,继关注点分离(Separation of concerns) 之后我们研究了安卓应用程序模块化(Modularizing Android Application)。我们通过应用程序模块化消除了依赖关系,提高了代码的安全性和可维护性,并通过复用在其他移动端项目中分离出的模块显著地提高了生产率。

很多早期的移动应用程序倾向于不花太多时间在制定包(package)策略上。在大多数情况下,多个类最开始被放在一个包内进行开发,随着应用程序逐步发展,一般会以activity、 fragment等组件为单位建立包并把相应的类放进去。若按照这种方式持续迭代下去,最终一个包内可能会存在非常多的类,这在维护的时候会成为一块很大的绊脚石。

我们已经成功分离了13个核心模块,但在模块内部仍然还是庞大的以组件为单位的包,而且包之间的依赖关系非常复杂。为解决这个问题我们决定进行包的重构。

这篇文章中我们将介绍怎样消除包之间的依赖关系,以便能够继续我们在之前文章中提到过的项目模块化进程。

我们决定对两种不同的包策略进行比较。

1. 按组件分包

按组件分包是指以activity、fragment、adaptor、handler等组件为单位进行分包。

com.your.company.activity

com.your.company.fragment

com.your.company.adapter

com.your.company.handler

2. 按功能分包

按功能分包是以各功能为单位进行分包。从结构上来看,activity、fragment、adaptor等可以组成一个功能,从而能把它们按照功能进行分离。同时随着功能个数的增加,可以按照功能为单位对其进行重构。

com.your.company.feature1.sub-feature1

com.your.company.feature1.sub-feature2

com.your.company.feature1.sub-feature3

com.your.company.feature2.sub-feature1

按组件分包与按功能分包的比较

可扩展性(Scalability)

按功能分包的显著优点就是可扩展性。每当有新的功能时我们都能轻松地生成新的包。但是当按组件进行分包时,如果你包里的类超过100个的话,开发者将需要花费大量时间来找到想要的类,万一忘了类名就更麻烦了。

可读性(Readability)

我们花几周或者几个月的时间来开发新的功能,但它并不总是能满足用户的需求。如果是基于组件分包进行开发,为了删除那些无法满足用户需求的功能,不得不修改每个相关联的组件(activity, fragment, handler, DTO 等)。然而如果是基于功能分包进行开发,这时就能把整个功能包删除掉 。不仅如此,基于功能的分包开发也能提高相关类的可读性以及对功能的理解。

依赖关系(Dependencies)

基于功能分包的开发也有助于减少依赖。大多数类将在功能包内部相互依赖,仅有部分公共代码会对外部产生依赖关系。同时对于一些类,也可以通过包访问修饰符进行细粒度的限制。

此外,还可以在按功能划分的包内按组件或层进一步细分。例如,如果是以MVP模式构成的包,可以按view、model和presenter等组件创建子包(sub-package)。由于清晰的组件划分,可读性和可维护性会得到提高,效率同样也能得到提升。

按功能分包及MVP模式应用示例

假设你创建了一个名为Login的功能包。如下图所示,我们可以建立名为model、presenter、view、util的子包。

fb458ae9a8a0b3d584a2ffc1975ca483.png

Fig1. Login feature package

当开发经理、开发者、设计师及各种团队成员在一起工作时,大家一定也像我们一样,常常关注如何有效地工作。我们通过按功能分包的组件间的交互,找到了最合理的方案。

公共类的思考

开发者在做基于功能分包的开发工作时,往往会考虑如何处理不同功能之间的公共功能或需要被共享的功能。在最小化重复代码和依赖关系的同时分离公共类,绝非易事。一种方法是将所有公共类放在上层的公共包中。

com.your.company.common.feature1

com.your.company.common.feature2

com.your.company.common.feature3

同时,只在功能内部被使用的公共类可以按照下面的方式放在功能包内。

com.your.company.feature1.common

com.your.company.feature1.sub-feature1

com.your.company.feature1.sub-feature2

Coupang的案例

直到最近,Coupang还是由按各个功能划分的开发团队组成。由此我们自然而然地以各团队为单位创建包并开展工作。因此我们在上层创建了common和domain两个包,并按照上面提到的方法配置了common 包,而domain包则是以每个功能创建一个包的方式构成。

大部分的电商都有搜索、登录、购物车等功能。并且在一个大的功能下面,融合了多个小功能。例如,搜索里面可能包括了首页搜索、地图搜索、自动完成等各种功能。我们觉得有必要将这些功能重构成独立的单元,并逐步地开展工作。

重构包的小建议

在重构包的时候有几点需要注意的事项。

注意检查XML(manifest、layout等)内声明的文件或类的路径。我们可以利用Android Studio的重构工具来修改这些路径,这样会更加安全。

此外,重构包后需要重新设置Proguard,但我们不想每次重新打包之后都重新设置,所以我们创建了一个标记用的接口并将其应用于所有需要的类。例如,我们为所有DTO创建了DTO接口,并统一了实现该接口的所有类的proguard配置。

Interface

public interface DTO {}

Proguard

-keep class * implements com.your.company.common.DTO { *; }

这使我们能在不对Proguard产生任何影响的情况下进行包重构的工作。

分析工具

为了分析重构包带来的提升,我们使用了多种工具并想在此作出推荐。

Code Iris

(https://plugins.jetbrains.com/idea/plugin/7324-code-iris)

一款Android Studio插件,能以可视化的方式展示项目中模块、包及类之间的依赖关系。

pk-dependency-graph

(https://github.com/alexzaitsev/apk-dependency-graph)

通过此工具能看到类之间的耦合状态。

MetricsReloaded

(https://plugins.jetbrains.com/idea/plugin/93metricsreloaded):

可通过表格图表分析有依赖关系的包和类。使用以上工具,我们能轻松测量依赖关系的数量并将其图表化。

ad952e52917e5f55be199e9d4f4ebdab.png

Fig2. Legacy Coupang App

在经过两个月的包重构后,我们看到了下面的结果。

a9188edb337a53eac30136ab032e64ef.png

Fig3. 包重构后的Coupang App

结论

总之,通过重构包我们提高了现有代码的健壮性,并完成了未来要进行的模块化工作的一大步。不仅是可扩展性和可读性公共类在各个功能中的识别和重用也容易多了。

现在我们能用MVP或MVVM模式以小的独立功能来构建包。下一篇文章中我们将会介绍模块化的策略。
本文出处:Coupang technology blog Team

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值