Khellendros 2020-06-01
英文学习 App Duolingo(多邻国)的 Android 版最初是使用 Java 开发的,并一直沿用了 5 年。两年后,它变成了 100% 的 Kotlin App!从代码可维护性和开发者满意度方面来看,这次迁移是一个巨大的成功。网上已经有很多 Kotlin 的学习资源,所以在这篇文章中,我们将重点介绍如何将一个有百万用户的 App 迁移到 Kotlin。
2018 年初,我们开始考虑使用 Kotlin,当时 Android 对 Kotlin 的支持还不到一年时间,而且不知道 Kotlin 会像现在这样流行,也不知道它会取代 Java 成为 Android 的开发首选语言。
我们当时的主要预期:
Duolingo 的所有 Android 开发人员每两周开一次例会,讨论最近和即将做出的平台变更和非正式的事后分析,并进行问答。前期的会议专门介绍 Kotlin,内容主要基于 Kotlin 官方语言指南、Kotlin Koans、Android 官方文档和 MindOrks 备忘单,等等。
然后,每个 Android 开发人员都分配到一些 Java 代码,负责将它们迁移到 Kotlin。我们让相对有 Kotlin 经验的开发人员担任“Kotlin checker”角色,让他们在代码评审期间分享最佳实践。这个角色的人数逐步增加,直到所有的 Android 开发人员都包含在内。
从一开始,我们就对 Kotlin 工具进行容器化,并在代码预提交和 GitHub 拉取请求状态检查中强制使用,以此来确保代码的一致性。
我们使用 detekt、IntelliJ Inspection、Android lint 和我们自己开发的基于正则表达式的 Splinter 来检查所有的 Kotlin 代码。
在代码自动格式化方面,我们在公司范围内使用了 ktlint,将其作为代码预提交 hook 的一部分。另一个工具是 IntelliJ Formatter,不过我们发现它在 Docker 中运行会慢一些。
在将 Java 代码减少到只有 10% 的时候,我们从 CI 管道中移除了 PMD、SpotBugs 和大部分检查工具。继续使用这些 Java 工具将会降低我们的开发速度,而且不会为我们提供太多的价值。
为了让代码转换的评审工作尽可能轻松,我们建议每个源文件的拉取请求至少包含三个单独的提交:
我们发现,将 Java 文件转换成 Kotlin 后,行数平均减少了 30% 左右,在某些情况下甚至减少了 90%!
虽然移植代码对于我们的 Android 平台工程师来说不是问题,但对于我们的产品团队来说可能会相对困难。我们鼓励产品团队的开发人员在空闲时间迁移经常修改的代码,还通过每天的排行榜比赛来游戏化这个过程。最终,产品团队的开发人员担起了一半的工作量。
Kotlin 的工具生态系统比 Java 的要小得多。尽管如此,它已经足够满足我们的需求了。
我们偶尔还是会遇到 NullPointerException 和 IllegalArgumentException,这些异常来自第三方 Java 依赖库(比如 Android 框架本身),它们没有遵循最佳实践,没有使用可空注解,以至于 Kotlin 编译器无法知道某些方法的参数或返回值可以为空。随着谷歌给它们的公共 API 加入注解,这种情况得到了改善。
不过,Kotlin 仍然缺乏对一些 Java 特性的原生支持,包括不太常见的超类静态受保护方法调用和神秘的超类构造函数调用,但这类问题很容易解决。
在 2018 年初引入 Kotlin 之前,我们的 Android 代码库的代码行数每年增长 46%。两年过去了,我们加入了很多新特性,活跃的贡献者数量增加了一倍多,而我们的代码库现在几乎只和以前一样大!
根据 NPS 数据,这一次 Android 开发人员的满意度增加了 129 个点,大多数开发人员认为是采用 Kotlin(以及我们的工具)起到了主要作用。NPS 的数据具体为:
https://en.wikipedia.org/wiki/Net_Promoter