PayU如何借助MVVM架构提升代码的可测试性:-www.deekpay.com
在本文中,我将介绍PayU如何将其应用程序和SDK迁移至MVVM架构,以增强代码的可测试性、可扩展性和可读性。在过去几年中,我们进行了多次用户界面(UI)的迭代更新,而核心业务逻辑基本保持不变(新增功能除外)。然而,在原有架构下,我们难以跟上业务发展所需的更新速度。因此,我们着重于重新设计底层架构,通过采用MVVM架构,使代码更加易读、可扩展,同时提高可测试性。
我们之前做了什么?
在此之前,我们遵循的是MVC模式。理论上,这个模式对我们来说似乎很合适,但随着代码库的扩大和UI迭代的增多,我们意识到代码库变得难以管理,原因有二:
每次UI迭代时,我们不仅更改UI代码,还更改业务逻辑。这直接表明我们的UI与业务逻辑没有完全分离。
随着代码库的扩大,我们的单元测试代码量减少——这意味着我们越来越依赖端到端测试。这本身就是一个不好的迹象,因为我们的测试金字塔被颠倒了。
我们正朝着错误的方向(从左到右)发展。
当我们尝试理解问题时,我们意识到视图(View)和控制器(Controller)都依赖于模型(Model)。此外,活动(Activity)和片段(Fragment)同时包含UI逻辑和控制器逻辑。因此,我们的单元测试代码量减少,代码变得难以管理。
MVC结构
MVVM架构的救赎
我们开始寻找更好的架构,这时MVVM成为了我们的救赎。甚至,谷歌也青睐MVVM。
MVVM代表模型-视图-视图模型:
模型(Model):代表应用程序的数据层。
视图(View):代表应用程序的UI逻辑。
视图模型(ViewModel):是视图的模型。它作为视图和模型之间的桥梁,并不直接引用视图。
MVVM架构消除了各个组件之间的紧密耦合。子组件不直接引用父组件,它们只通过可观察属性进行引用。注意,每个组件只依赖于下一级组件。这种设计创造了连贯且愉悦的用户体验。
上述图表中的另一个重要组件是仓库(Repository)模块。它处理数据操作。它提供了一个清晰的API,以便应用程序的其他部分可以轻松检索数据。它知道从哪里获取数据以及数据更新时需要执行哪些API调用。你可以将仓库视为不同数据源(如持久模型、网络服务和缓存)之间的调解器。
LiveData是一个可观察的数据持有者。应用程序的其他组件可以使用这个持有者监控对象的变化,而无需创建显式和固定的依赖路径。LiveData组件还尊重应用程序组件(如活动、片段和服务)的生命周期状态,并包含清理逻辑以防止对象泄漏和过度内存消耗。
优点
关注点分离:将所有代码写入Activity或Fragment是一个常见的错误。UI类应该只包含处理UI和操作系统交互的逻辑。通过保持这些类尽可能简洁,你可以避免许多与生命周期相关的问题。MVVM让你确保每种类型的类只负责一种任务。
可测试性:用户界面和交互可以通过仪器测试用例(Espresso库)进行测试。视图模型(ViewModels)和仓库(Repository)可以使用JUnit测试。
可扩展性:你可以轻松引入UI更新。添加新功能时无需重构或更改现有代码库的大部分内容。我们可以更轻松地插入和拔出组件。
可管理性:代码库更易于管理——所有UI逻辑都在一个地方,业务逻辑和数据逻辑在另一个地方。
缺点
开始使用MVVM和添加新功能可能需要一些模式经验。相对来说,学习曲线较陡。
遵循MVVM模式可能会导致创建更多的Java类。
结语
在构建任何应用程序时,选择正确的架构模式至关重要——没有固定的“一刀切”模式。
在我们的案例中,MVVM证明是一个有用的模式,因为我们有一个UI丰富的产品,经常进行UI迭代更新,我们希望关注产品的可测试性,并希望实现关注点的分离,以便我们只需更改代码库的相关组件,而不影响其他代码。MVVM架构对我们来说是一个完美的选择!