Szhangbiao's blog

记录一些让自己可以回忆的东西

0%

Singapore知名保险App项目重构路线

该项目大概是从 2015 年开始迭代到现在的 v2.11.1,其中主要的三个大的模块ia(incomeapp)ot(orangetravel)和oh(orangehealth)分别有三个团队维护,我司在 2021 年开始负责并重构了ia模块也就是现在的nia,2022 年 10 月份开始由我司开始重构整个 app,把目前的 MVC 的开发模式重构为基于 Kotlin 的 MVVM 模式

概要

新版本的重构重点是把旧版的 MVC 架构重构当前比较流行的基于 Google Jetpack
的 MVVM 架构

经典的 Android MVVM 架构图:
image

重构周期

项目重构周期为三个月(初定),期间的大致规划如下:

  1. 9 月份开始接手搭建基础框架并整理重构路线
  2. 10 月份把现有业务逻辑代码改成 MVVM 的实现方式并添加 Unit Test
  3. 11 月份根据新的 design 图重构 UI 部分并把主体业务逻辑跑通
  4. 12 月份 QA 上手测试和开发修复 bug

注: 以上是初步计划,后续很大概率会有改动,影响有前期对项目的认知不足导致的工期的延长、人员的增减等不确定因素

重构要点

迁移方式

  1. 直接移动类到相应的module下然后重命名,这种方式是涉及更改的类会比较多
  2. 新建一个在功能上优化后的类,(可参考 LocalStorage 的实现)在旧版的实现上请加上 Deprecated 注解,以此让团队的其他成员了解此类有新的实现

App 模块化后的架构

目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app
insurance
├── core
│ ├── analytics
│ ├── common
│ ├── config
│ ├── model
│ ├── network
│ ├── storage
│ ├── utils
│ └── widget
└── feature
├── auth
├── health
├── home
└── travel

基于 MVVM 架构重构后的项目结构图:

image

注:如果在各模块的build.gradle里用api来引用其他模块,那么引用关系大致如上图,但是使用api会导致 Gradle 编译变慢,所以现在项目里都是用implementation来引用其他模块和第三方库

项目结构模块说明:

模块名 作用 说明
:app v2.11.1 及以前的代码都在里面,包括网络、本地存储、Firebase Config、事件统计、业务逻辑、UI 等全部功能 随着 app 业务逐渐增大、代码逐渐复杂,单 Module 工程显然不足以应对,借着这次 MVVM 重构的机会,把各个功能代码迁移到独立的 module 里去,其中包括 nia(ia)、ot、oh 等主要功能模块
:insurance 重构后的主模块,insurance app 的一系列设置和 feature 模块交互提供路由跳转等实现 重构后的主模块相对 app 模块来说就像是一个壳,主要的功能都迁移到一个独立的 library 模块中,除了一些必要的代码实现
:feature:home 旧版nia模块的主要内容都会迁移到此 module,已知的有 dashboard、account 等功能 待定
:feature:auth 旧版nia模块里的 login、register 和 OTP verify 等页面,这些页面与其他 feature 交互不频繁属于一次性交互 待定
:feature:health 旧版oh模块的页面迁移到此 module,包括 challenge、rewards、friends 和 earn points 等功能 待定
:feature:travel 旧版ot模块的页面迁移到此 module 待定
:feature: … 模块名待定,如果觉得以上 feature 划分不合理或者深入了解niaotoh后可以再创建一个单独的 module 划分独立 feature 模块的原则是 module 内的页面相对内聚,除了入口页面外其他的页面与其他 feature 模块并无交互
:core:common 为各个 feature 模块提供基础通用的实现,定义 feature 模块路由交互的接口 提供各种 base 类,其中 BaseFragment 中提供 UI 上通用的业务逻辑处理
:core:storage 迁移旧版 database、mmkv、security-crypto 等本地存储 禁止 room 允许主线程查询的设置、封装基于 mmkv 的用户信息存储,避免太过分散的情况,添加 unit test,迁移旧版的 SharedPreference 的实现到此 module 是为了方便做 unit test,后续考虑加入内存缓存的实现包括旧版中 otpToken 等一次性的值
:core:network 基于 Retrofit、Moshi 和 kotlin flow 的网络请求模块 摈弃了旧版的基于 Volley 的网络请求实现,同时兼容了 Glide 加载 income 图片需要添加 header 的操作
:core:config 获取 Firebase Remote Config 模块,主要封装了获取 config 的逻辑 包括 config 的获取、缓存和容灾处理等逻辑,向外提供接口,逻辑实现主要在 module 内部
:core:analytics 事件统计模块(待完善) 目前事件统计功能实现太过分散,没有形成统一管理
:core:widget 自定义控件模块(待完善) 待新设计图出来后可重新封装或者在旧版的基础上更改迁移过来
:core:model 实体类模块,包括网络请求和响应、事件统计和描述页面数据等 model 主要从旧版的 model 中迁移或封装而来,必要时可更改类名使其更简洁易读
:core:utils 工具类模块,为其他模块提供通用的工具类包括各种 utils 和 extension 类 内部也迁移了旧版的一些代码,主要是为了向其他的模块的 unit test 提供支持,在后续迭代几个版本后确认后可安全删除

更多内容可以参考掘金这篇关于 模块化 的文章, 重构后的代码里有很多的借鉴, 还有官方 github 的 sample 工程

多 Module 交互模型

官方提供的 ViewModel 的作用域

image

数据交互模型

image

参考 用 Kotlin Flow 解决 Android 开发中的痛点问题

技术选型

  • Gradle 构建 - ktx 配合 MavenPom 参考将构建配置从 Groovy 迁移到 KTS
  • Hilt-Android - 注解框架 参考Hilt 使用详解
  • Navigation - 路由框架 官方介绍
  • Kotlin Flow & Channel - Flow、StateFlow、SharedFlow、ChannelFlow 等
  • MVI 架构 - 解决 ViewModel 和 View 层通过 LiveData 通信的一些问题 参考这边文章
  • Jetpack 组件 - Lifecycle、ViewModel、Room、WorkManager、LiveData 等
  • 网络请求框架 - Retrofit + Moshi + Okhttp
  • 日期处理 - JodaTime
  • Log 处理 - Timber
  • 图片加载 - Glide