看起来,这是一个旧的代码库!
#编程 #重构 #kotlin #android

如果您是一名工程师,已经从事该行业已有九或十年的时间,那么您可能会经历过“状态如此出色”的项目。

你知道我在说什么。那些第一位工程师决定根据他们从媒介中浏览的一些随机文章来实现MVP体系结构的项目。

然后,当Jenga塔在倒塌的边缘摇晃时,工程师认为是时候“寻找新的冒险”了,因此必须雇用一个新的开发人员!

新开发人员认为上一位不知道他们在做什么,因此他们决定在每个屏幕上使用自定义的底部表段frag毛。当然,这将起作用!

不是。

,这位工程师又必须去寻找新的挑战。在5年的时间内重复此5次,您将不再有一块软件 - 您有炸弹。您有一只可乐,一旦您从货架上抓住它,就会在您的手中爆炸,并留下充满弹片的脸。

现在是您的转弯。我将分享一些我学会的东西,以帮助您应对这些情况。希望其中一些技巧可能会派上用场。

删除未使用的资源

发行

您经常浏览代码库,而且经常看不到完全灰色,未使用的代码部分。没有保留代码“以防万一”,您要么使用代码,要么不保留剩菜,这只是会使人们感到困惑,这可能是一个更深层次的问题的症状。

解决方案

Android Studio在Rebactor下具有“删除未使用的资源”工具

Image description

,如果您对某些Android Studio Picks感到不满意,则可以预览删除未使用资源的外观,并排除其中的某些删除。

PR模板

发行

因此,质量保证工程师抱怨说,您的团队提交的每个修复程序都像蝴蝶效应:它创建了3个新的不同错误,或者他们说修复/功能甚至根本不起作用。这就是我所说的后期“我不给无花果”综合征。代码库是如此脆弱,因此容易出现错误,以至于没有人关心测试内容,甚至在本地运行这些更改。

解决方案

为团队设置PR模板。不必使用超长的烦人到填充表格,只要每次工程师想要提交PR时,都可以完成两个项目即可完成。对其中的内容的简短描述,以及工程师的视频演练,以解释更改并显示该功能的工作方式。

Image description

您知道Slack可以让您录制和下载视频吗?

Image description

您可以使用该工具录制视频,然后下载它们,然后将它们拖放到PR描述中。这是一块小菜一碟,不会花费超过5分钟。但是,如果您的工程师甚至找不到时间搅动5分钟的视频来解释他们的作品,那么,那是另一个蛋糕。

Kotlin基础知识

发行

您浏览代码,并查看可重新分配(可变)变量的可变数据类型

var someLiveData = MutableLiveData<Something>()

var someCollection = mutableListOf<Something>()

或者您看到滥用var属性的数据类结构

data class Something(
  var prop1: SomethingElse?,
  var prop2: SomethingElse?
  // ...
)

这通常是没有完全从Java迁移到Kotlin的工程师的症状。重要的是要充分理解诸如Mustability和nullability之类的概念。

解决方案

这是缺乏Kotlin基础知识的症状。我想推迟一段时间以前阅读的超级热心文章:

https://www.javacodegeeks.com/starting-with-kotlin-cheatsheet

科技汤

发行

好的,在应用程序的不同角落,您的屏幕要么使用ViewBinding,Kotlin Synthetics,Butterknife(因为为什么不呢?)或Composables。

有些屏幕使用Livedata,Flow或Kotlin通道将ViewModels回到UI,而有些则使用数据框。

通过这个项目的每位工程师都有自己独特的天才做事的方式……因为显然,他们面前的家伙是一个完整的白痴。

解决方案

尝试在团队认为最佳实践和您在代码库中已经拥有的最佳实践之间找到平衡。安排每周或每两周一次与工程团队举行会议,请一层通过架构进行一层,并确定从现在开始的最佳实践。例如:

“好吧,我们将改造用于API调用,我们是否将响应包装在Response包装器上以进行状态响应或我们不在乎吗?”

“好吧,从现在开始,我们如何与UI通信?我们有所有这些选项,我们使用什么,为什么?”

“好吧,我们使用喷气背包堆肥还是使用其他东西作为UI框架?”

您一层逐层进行,找出可用的选项(请不要将另一个工具推入混合物!),然后选择一个。如果可能的话,请记录某个地方的概念或Wiki或其他任何内容,但要记录一下它同意某事而不写下它与什么都不做。

导航汤

发行

这就像一本选择自己的冒险书...除了在应用程序导航之地!该应用程序的某些部分使用导航图。有些正在进行一项活动,许多自定义视图方法。有些是全屏对话框。其他的是全高底部表面段。您将选择什么应用程序之旅?

解决方案

与上述相同,与团队的其余部分同步,选择一个解决方案。我建议您决定什么,您都会使用片段。考虑一下提供某种UI的所有第三方库;他们都通过活动或碎片来做到这一点。应用程序的每个流量的目标(登录流量,帐户创建流,入门流等)应完全是公开每个流动,就好像您共享一个SDK一样开发人员。

当然,这需要更多的技术头脑风暴,具体取决于您手头的意大利面条 - 我建议您继续使用每个屏幕的应用程序都有一个基础类别(智慧的那些很棒的面条),您会继续使用它们。听我说:

假设您的应用程序使用BaseSomethingFragment工作,每个屏幕都在此基类上扩展。在内部,BaseSomethingFragmentBottomSheetDialogFragment延伸,然后对其进行调整,因此提示在全高。

您可以做的事情是调整此基类,以便它具有FragmentViewContainer并在内部使用导航图,这样您可以使用片段创建其余的屏幕,最终将每个屏幕移动到裸露的片段中而不是使用那个基类。

只是一个主意,这不是一个万无一失的计划,但它会给您一次一次做事的机会。

通过模块隔离新代码

发行

鉴于该应用是一个大的单片:app模块,包含上述所有项目,我们如何才能开始实现新的方法并开始分开组件?

解决方案

日落应用模块。所有的应用程序都可以分为不同的流。例如,当用户通过登录屏幕时,那就是登录流程 - 可能是2个或3个屏幕的集合,但这是一个独立的流。您可能还会有一个入职流,帐户创建流等等

这些流中的每一个都应包含在特征模块中(仅是图书馆模块的幻想名称),并且这些特征模块中的每一个都应完全独立于彼此,因此我们可以防止依赖关系铲除。您可以逐步进行此操作:

首先,您拥有单片应用模块

Image description

现在,为了让事情保持整洁,让我们重命名将模块重命名到:app-legacy中,只是每个人都知道我们不应该继续在其中添加东西。

Image description

我们将创建一个新的应用程序模块,即:company-app,并取决于旧的:legacy-app模块。我们还将:legacy-app模块从应用程序模块转换为库模块。

Image description

很可能,您的旧:legacy-app模块在这种情况下具有Application类,Application类通常用代码高度肿。因此,要启动新鲜,您可以让您的新的:company-app应用程序模块具有自己的Application类,可以从旧的类别延伸。您也可以将旧的CompanyApp标记为@Deprecated,以防止进一步的东西在其中添加。

Image description

您可能还必须将许多插件从:legacy-app移至新的:company-app应用程序模块。例如,如果您使用的是firebase和google-service.json,则可能必须将它们移到那里,因为它们需要插入应用程序模块。

现在,您可以创建完全独立的功能模块来重构现有流或创建新的流量。假设我们有一个账户创建流,它消除了错误,我们想将其提取到一个孤立的模块中,以便我们可以安全地重构。

首先,我们为此新流量创建一个新的库模块。

Image description

现在,我们将所有类别的Fragments移动所有类别的所有类别,这些内容特定于该新的库模块。如果在流之间重复使用了某些东西,则假设您有一个SharedPreferences包装器,它留在:app-legacy模块中。

如果我们想在功能模块之间导航该怎么办?假设我们有另一个应用程序流的功能模块。

Image description

好吧,您可以使用导航类。您可以在:app-legacy中声明一个接口,该接口揭示了每个流中每个屏幕的入口点。类似:

interface MyNavigationProvider {
   fun getLoginFragment(context: Context): `BaseSomethingFragment`
   fun getUserProfileDetail(context: Context): Intent
   // ...
}

您可以提供碎片或意图,无论哪种最适合您的建筑。

此界面将在NewCompanyApp应用程序类中实现,并且由于:company-app模块将所有功能模块绑定在一起。

如果您需要从一个功能模块中的一个屏幕跳到另一个屏幕,那么您唯一需要做的就是将应用程序上下文投放到MyNavigationProvider接口中,该接口在:app-legacy

中声明了

类似:

getApplicationContext() as? MyNavigationProvider

就是这样!

现在,不要认为这项工作已经完成。这是一条漫长的道路上的第一步。最终,我尝试做的是将:app-legacy变成一个:core模块,只有所有功能模块共有的东西。我尝试将UI和其他所有内容提取到功能模块中。

但至少这应该足以为您的团队提供独立创建新流程的方法。

Image description

此后您可以做很多事情,您可以将所有基础UI提取到:design-system库模块中,因此您将应用程序的外观封装在一个地方,但是我强烈建议您首先获得基础知识工作,然后您可以开始考虑添加额外的东西。

设置编码标准

发行

每个人提交的每个公关似乎都会由于代码格式而进行的更改要比实际实质更大 - 就像单行错误的bugfix需要30个更改;一个用于错误,29用于进口变为通配符导入或tab-formatting。谁知道代码格式可能如此复杂?

解决方案

将一些.idea文件推入存储库中,或者在整个团队中共享代码样式配置。

就这样

最后,与团队中的每个人,工程师和高管管理中的每个人都设定了期望,将所有内容放在桌子上,以便每个人都知道发生了什么和需要解决的问题。

我敢肯定,大多数人都会哭泣“微观管理!”在我的一些建议中,嘿,每个人都想推动代码并假装它正在起作用,这是您的特权。那不是我的事。