2月26日、Engineering at Metaで「Meta が Java コードベースを Kotlin に変換する方法(How Meta is translating its Java codebase to Kotlin)」と題した記事が公開された。この記事では、数千万行に及ぶMetaのAndroid向けJavaコードをKotlinに翻訳する大規模な取り組みについて詳しく紹介されている。

以下に、その内容を簡潔にまとめて紹介する。
Kotlinator — JavaからKotlinへの自動変換ツール
Metaでは、何年にもわたってAndroidコードベース全体をJavaからKotlinへ移行するプロジェクトを進めている。既存コードは世界有数の規模だと思われるが、 すでに半分以上をKotlinへ移行し、さらに残りの部分を継続して変換している という。
翻訳にあたっては、Metaが独自に開発した「 Kotlinator 」という自動変換ツールを用いている。
Metaがコードの変換を始めた当初は、(業界のほとんどの人々と同様に)Intellij IDE のボタンを繰り返しクリックすることで段階的に移行を始めたという。このボタンは、一般に「J2K」として知られるIntellij の翻訳ツールを起動する。
しかしこのアプローチでは、Metaの規模のコードベースには対応できないことがすぐに明らかになった。すべてのAndroid コードベースを翻訳するには、そのボタンをクリックして、実行にかかる数分を待つという作業を 10 万回近く行う必要がある。
そこでMetaは変換プロセスを自動化するため、J2KをベースとしてKotlinatorを開発した。現在、このツールは次の 6 つのフェーズで構成されている。
- 「Deep」ビルド
- 変換前のコードをビルドし、シンボル解決を明確にする工程
- 前処理(Preprocessing)
- null可能性の調整、カスタムDIフレームワークへの対応、J2K対応など約50個の調整を行う
- ヘッドレスJ2K
- IDEに頼らず、サーバー上でまとめて実行できるよう改良したJ2Kを使う
- 後処理(Postprocessing)
- Android特有の処理や、よりKotlin的なコードに近づけるための約150ステップの調整を施す
- リンター実行
- 自動修正機能付きリンターを通すことで、コードの品質を高める
- ビルドエラーに基づく修正
- 最後にビルドを試し、残ったエラーを解析して再度修正を加える
これにより、大量のJavaコードをKotlinへ翻訳しながらビルド可能な状態を保ち、開発者の手作業を最小化する仕組みを整えている。
例えば、以下はKotlinatorを用いてJavaインターフェースをKotlinに変換した例である。
(Javaから変換されたKotlinインターフェースの例)
interface JustConverted {
val name: String // 以前はgetNameというメソッドだった
}
class ConvertedAWhileAgo : JustConverted {
override val name: String = "JustConvertedImpl"
}
このように、JavaのgetterをKotlinのプロパティへ置き換えたり、null安全を確保するための注釈追加や型変換を自動的に補完できるよう前処理が行われる。
何はともあれnull安全!
さらに、記事内ではnull安全(nullability)を扱う上での注意点にも言及している。Javaのアノテーションに抜けがあると変換後のKotlinコードで不要な「!!」を多用し、意図せぬNullPointerExceptionを引き起こしやすくなるため、大規模コードベースに潜む非null安全コードをいかに検出し修正するかが鍵だとしている。
特に以下のような例を紹介し、Javaで「null安全」とされている箇所でも、Kotlin変換で新たな問題が表面化する場合があると指摘している。
(NullableなBooleanを扱う際の例)
/* Javaでの元のコード */
if (foo != null && !foo.isEnabled) {
println("Foo is not null and disabled")
}
/* 誤ったKotlin変換例 */
if (foo?.isEnabled != true) {
println("Foo is not null and disabled")
}
/* 正しいKotlin例 */
if (foo?.isEnabled == false) {
println("Foo is not null and disabled")
}
現時点でMetaのAndroidコードベースの半数以上をKotlinへ移行し終えているものの、まだ残る複雑な箇所の自動化や、JetBrainsとの協力による翻訳ツール(J2K)の改善を進める必要がある。大規模コードベースの完全なKotlin化を目指すうえで、引き続き多くの企業やコミュニティと情報を共有しながら作業を続けていくという。この取り組みは、JavaコードをKotlinに変換したいと考えるすべての企業にとって有益なツールの開発につながるだろう。
詳細は[How Meta is translating its Java codebase to Kotlin]]を参照していただきたい。