必要性是创造之母.

柏拉图

每个想法都源于需求, 这次也不破例. 在 Whatnot 的日常功用开发过程中, 我一直在尽力跟上事务开展的脚步. 我有必要在一周内完成一个恰当巨大的功用, 保证全部按预期运转. 但怎么做呢? 为了供给高质量的软件, 咱们应该少走哪些弯路? 让我一步一步来解说.

首要, 让咱们把重点放在我以为阻止编码速度的工作上.

  • 我真丢人啊! 从事务视点和规划视点来看, 在编写单元测验的一起, 还要完成每两小时就会改变一次的边际功用是恰当苦楚的.
  • 手动测验杂乱的用户途径令人沮丧, 而且会破坏专心力.
  • 运用的构建时刻. 杂乱的代码库会下降开发速度. 咱们都经历过这种苦楚!

越过单元测验!

越过单元测验会产生一个不好的副作用, 那便是无法独自履行和测验代码. 每分钟都在设备上构建运用十分耗时, 咱们便是这样消耗了大量的开发周期. 另一个危险是在不引进新过错的状况下修正过错. 假如没有牢靠的回归套件, 这几乎是不或许的.

我决议在功用开发期间能够不进行单元测验, 在产品发布后再编写单元测验. 与此一起, 我还支付额定的尽力, 保证我编写的代码是可测验的, 洁净的. 这并不是一个巨大的应战, 由于咱们的架构构建器现已十分老练和强壮. 你猜怎么着? 越过测验驱动开发为我节省了大量时刻! 我能够快速编写代码, 并毫不费力地调整完成.

不幸的是, 在设备上进行测验破坏了我的注意力, 我知道我有必要为此做点什么. 让咱们试试!

‍ 在设备上测验

关于 Android 工程师来说, 快速的 Android 模拟器, 增量编译和构建缓存无疑是最好的东西之一. 每隔几分钟运转一次运用并不是一件很苦楚的事, 但假如咱们需求测验特定的验证场景, 过错状况或空途径呢? 这些杂乱的用户途径或许会消耗咱们一些时刻和精力. 正如我之前提到的, 单元测验能够让咱们阻隔运转代码, 设置初始状况并取得快速反应, 从而帮助咱们处理这个问题. 咱们怎么才能将这种方法运用到根本不存在测验的世界中呢?

为了答复这个问题, 请允许我扼要介绍一下咱们的 Whatnot Android 技术栈. 在Whatnot, 咱们正在构建实时购物和市场, 在这儿您能够购买, 出售和发现您喜爱的产品. 除了实时流媒体, 咱们还有大量的卖家和买家功用, 以及丰富的原生用户界面体会. 咱们在早期阶段就采用了 Jetpack Compose, 这一决议不只缩短了开发周期, 还让开发人员感到愉悦和满足.

Jetpack Compose 是现代安卓用户界面东西包, 能够大大加快开发速度. 所生成的代码不只更简略, 而且更优雅, 更简洁. 咱们还运用 Jetpack ViewModel 为咱们的可组合用户界面供给正确的状况. 扼要阐明: MVI 上线. ViewModel 只不过是一个容器, 它粘合了几个函数, 这些函数依据网络成果还原状况, 并将其推送到视图层.

⚒️ 修正快速反应回路

现在, 当你知道咱们运用了哪些东西后, 我能够开端解说我是怎么想出一个处理方案来修正损坏的反应环路的.

我的方针是建立一个简便的处理方案, 以便在运转用户界面的一起, 孤立地运转模型层. 此外, 我还希望它快速, 牢靠并具有预测性. 我想到了几个问题:

  1. 怎么阻隔运转Compose代码?
  2. 怎么阻隔运转模型逻辑?
  3. 怎么构建一组预界说状况, 用于测验回归?

首要, 阻隔运转 @Composable 函数十分简略. Jetpack Compose 附带了一个额定的东西工件, 能够直接在 Android Studio Preview 中烘托它.

debugImplementation("androidx.compose.ui:ui-tooling:VERSION")
implementation("androidx.compose.ui:ui-tooling-preview:VERSION")

这关于创立一组变体并以简略便利的方式对其进行测验十分便利. 下面是在 Whatnot 规划系统中运用 @Preview 可视化所有二级按钮状况的示例.

@Preview驱动 Jetpack Compose 开发

下一个难题有点难. 咱们怎么运用 @Preview 来独自运转整个屏幕乃至整个用户流程? 用 Compose 编写的常规屏幕比按钮有更杂乱的功用参数, 但这是个问题吗? 这是一个应战!

让咱们从界说屏幕的公共 API 开端.

正如你所看到的, 经过供给函数参数, 咱们能够在 @Preview 中将其作为普通 Composable 运转.

ScreenViewModel 是运用假用例手艺创立的. 经过运用另一个 Compose 东西, 咱们能够做得更好. @PreviewParameter!

这很好, 不是吗? 经过运用 PreviewParameterProvider 和 @PreviewParameter, 咱们能够界说任意多的事例. 所有事例都将在 Android Studio 预览版中自动呈现. 它们采用与 JUnit 测验参数相同的编码方法.

到目前为止, 咱们取得了哪些成果? 咱们知道了怎么独自烘托屏幕及其模型逻辑. 这很好, 但这足以处理反应环路的问题吗? 还不行, 由于咱们还不知道怎么运用 @Preview 来运转而不只仅是烘托杂乱的用户途径.

为了简化杂乱的用户途径, 幻想一下, 咱们有一个用户流程, 该流程会显示一个发货配置文件列表, 并供给增加, 更新和删除每个配置文件的功用. 除此之外, 每个屏幕都应恰当处理空, 过错和数据状况. 咱们还需求一些高级表单验证, 以保证用户知道该做什么. 咱们的 Whatnot 运用中就有这样的流程, 让咱们以它为例.

Whatnot 发货配置文件用户流程

正如您所看到的, 视频只展示了流程的一部分, 由于它仅从 “配置文件 “选项卡开端. 实践上, 测验每个用例都会愈加杂乱, 由于咱们需求登录, 进入正确的界面, 并保证所有功用标志和配置都设置正确. 不过不要害怕. 咱们能够运用 @Preview 独立运转流程!

提到细节, 值得一提的是咱们运用了 Compose Navigation, 它只不过是一个 Jetpack 导航组件. 它让生活变得更轻松, 并带有一些便利的动画和东西.

运送配置文件流程的进口看起来是这样的:

哦, 天哪, 乍一看还挺吓人的, 但让我从更高层次的视点来解说一下这儿发生了什么.

  1. shippingProfileFlow 是一个扩展函数, 能够轻松衔接到任何导航图. 这使得流程能够在整个代码库中重复运用.
  2. shippingProfileFlow 函数界说了六个不同的导航目的地, 如列表, 创立, 修改, 两种过错类型以及一些成本优化信息.
  3. 最重要的是最终三个参数: viewModelStoreOwnerProvider, shippingProfilesViewModelProvider, shippingProfileViewModelProvider. 它们带来了实践的 “魔法”, 让咱们能够注入假的模型供给程序, 并阻隔运转代码.
  4. 默许状况下, shippingProfilesViewModelProvider 具有真实的完成, 可依据 LocalViewModelStoreOwner.current 注入正确的目标实例.
  5. 默许状况下, shippingProfileViewModelProvider 的实践完成是依据作为参数传递的viewModelStoreOwnerProvider注入一个正确的目标实例.

这种技术与众所周知的依赖注入没什么不同. 有了这些, 咱们就能够独自增加 @Preview 代码和RENDER流程了.

首要, 界说 @PreviewParameter(s).

然后增加 @Preview 函数.

这段代码中最吵闹的部分是用于创立 modalBottomSheetLayout 的辅佐函数, 但我决议不介绍它, 由于它在这儿没有任何实践价值. 相同的规矩也适用于虚伪替换.

最终! 咱们能够在 Android Studio 预览版中烘托咱们的流程了.

@Preview驱动 Jetpack Compose 开发

成功了! 那么在模拟器上运转呢?

正如你所看到的, 流程在阻隔状况下运转, 咱们只需不到一秒钟的时刻就能玩转它们. 我能够将”静态”的 @Preview 转变为完全老练的 @Preview 驱动开发东西. 它加快了代码编写速度, 只需在数据供给程序中编写几行代码, 就能假造出不同的杂乱场景. 除此之外, @Preview 事例仍是很好的文档和手动回归集.

主要收获

我知道, 这或许需求消化许多东西, 但假如你现已在 Jetpack ViewModel 中运用了 Compose, 那么在你的代码库中运用相同的战略应该不难.

再回到阻止编码速度的当地.

  1. 越过编写单元测验并不是我推荐的做法, 但这样能够节省时刻. 事实上, 时刻不是省下来的, 而是从未来借来的! 发布后, 我编写了完好的单元测验套件, 以加快回归速度. 这花了我一天时刻, 由于事务逻辑和用户体会都现已处理了.
  2. 运用 @Preview 运转杂乱的用户途径改变了我的游戏规矩! 超级易于保护, 牢靠且快速!
    1. 增量构建时刻不到两秒, 经过 @PreviewParameter 进行假造简略明了.

总而言之, 假如你还没有运用Compose @Preview 东西, 我十分鼓励你开端运用它. 在 Whatnot, 咱们正在实施Compose规划系统, 我无法幻想没有交互式 @Preview 的状况.