MetaがAndroid開発をJavaからKotlinへ移行した理由と方法
(engineering.fb.com)- MetaのAndroidリポジトリは、Facebook、Instagram、Messenger、Quest などを含む巨大なリポジトリ
- 現在、約1000万行を超えるKotlinコードを含んでいる
Kotlinへ移行した理由
- 人気以外にも主な利点がある
- Nullability : NPEはMetaで共通する問題だったためさまざまな対策をしてきたが、Kotlinの組み込みNullability処理のほうがはるかに強力で、作業もしやすい
- 関数型プログラミング : Kotlinのインライン関数とラムダ式により、実行速度を落とさずにFPスタイルを適用できる
- より短いコード
- DSL / Type-safe Builder
- もちろん無視できない小さな欠点もある
- 別の言語を導入することで、混在したコードベースをかなり長い間維持しなければならない点
- Kotlinは人気があるとはいえ、その人気にはJavaとのギャップがある。そのためツールが少なく、多くのKotlinツールはKotlinとJavaの相互運用性を考慮する必要があるため実装が複雑になる
- 最大の懸念はビルド時間だった。Kotlinのビルド時間がJavaより遅くなる可能性があることは最初から分かっていた。遅いビルド時間は開発者体験にとって好ましくない
移行へのアプローチ
- Kotlinへの移行は驚くほど簡単である一方で、非常に複雑でもあった
- J2K(Java To Kotlin Converter)があるので便利ではあるが、それでも複雑だった
- J2Kが常に正確とは限らず、JavaとKotlinの相互運用性がいくつかの極端なケースを生む
- 移行には2つの選択肢があった
- 新しいコードだけをKotlinで書き、既存コードの大半はJavaのままにする
- 利点は作業量が少ないことだが、2言語の混在によってKotlinでプラットフォーム型を使うことになり、nullポインタ参照でクラッシュが発生することがある。
また、Javaでは型パラメータをNullableとしてタグ付けできないことがある(最近まで)うえ、Kotlinのオーバーロード規則はnull許容かどうかを考慮するが、Javaのオーバーロード規則はそれを考慮しないという問題もある
- 利点は作業量が少ないことだが、2言語の混在によってKotlinでプラットフォーム型を使うことになり、nullポインタ参照でクラッシュが発生することがある。
- すべての社内コードをKotlinに変換することを試みる
- 新しいコードだけをKotlinで書き、既存コードの大半はJavaのままにする
実際の移行方法
- 2つの選択肢をどちらも検討したうえで、すべてのコードをKotlinに変換することを目標に決定
- 最初はやや遅かったが、いくつかのブロッカーを解消してからは大規模変換が可能になった
- 現在はFacebook、Messenger、InstagramそれぞれのAndroidアプリが100万行のKotlinコードを含んでおり、変換率は徐々に上がっている
- 現在、Androidコードベース全体には1000万行のKotlinコードがある
Unblocking
- 変換を始めた当初、いくつかの問題が発生した
- バイトコードのパターンのため、Redexの更新が必要だった
- 一部の内部ライブラリは性能のためにバイトコード変換を行っており、これがKotlinでは動作しなかった
- 内部で多くの最適化をしているなら、似たような問題が起こるはず
- 既存ツールにも問題が発生した
- コードレビューやWikiなどでKotlinのシンタックスハイライトが効かなかったため、Pygmentsを更新した
- Kotlinフォーマッタである Ktfmt を別途開発した
移行を加速する
- ツールの準備が整い、コードをKotlinへ変換する準備ができた
- しかし各移行では、手作業で進めなければならないボイラープレートコードが多かった
- J2Kは汎用ツールなので、コードそのものを理解しているわけではない。このため多くの手作業が必要だった
- たとえばJUnitのテスト規則のようなもの
- そこでJ2Kを3段階パイプラインの中央に置いた
- まずJavaパッケージを1つ取り出し、Kotlinへ変換する準備を行う。バグ修正や内部ツールに必要な変換もここで行う
- 次にスクリプトでJ2Kを自動実行する
- 最後に新しいKotlinファイルを後処理する。これが最も重要。自動リファクタリングやリンタなどをヘッドレスモードで実行する
- 自動化ですべての問題を解決できるわけではないが、共通するものを優先して対処した
Kotlin移行で学んだこと
- コード量が減った
- 実行速度は維持
- ビルドサイズは問題ではない
- 長くなったビルド時間の問題を解決 : KSP(Kotlin Symbol Processing API)を使用
4件のコメント
良い記事の共有ありがとうございます。個人的に Kotlin を最初に使ったときは、Java より便利な点が多くて良いと思いましたし、これからは Kotlin が主流になるのではないかとも感じていましたが、しばらく使ってみると、まだ Java のほうが良いと思える部分も多いですね。
Android は Kotlin でも問題ないと思いますが、他の環境(Spring など)では、安定性が重要ならまだ Java のほうがより良い選択だと思います。
安定性の事例を一つだけ教えていただけますか? まだ経験が浅く、そのような事例に出会ったことがないので、とても気になります。
JetBrainsが次々とリリースを出しているからかもしれませんが、意外とコンパイラのバグ修正が多いです。
https://github.com/JetBrains/kotlin/releases/tag/v1.7.20
コンパイラ自体が落ちることもしばしばありますし(これはまだリリース前なのでその点では大丈夫ですが)、生成物にも時々バグが含まれます。
さらにAndroidの場合は、R8 bytecode optimiser も Kotlin のバージョンを選びます。
なぜなら、Kotlin コード専用の最適化機能があるのに、これに関する公式の互換性テーブル文書(Android Gradle Plugin : Kotlin Version)がありません。..
そのため、Android プロジェクトで Kotlin のバージョンを変更するときは注意が必要です;;;
関連バグレポート : https://issuetracker.google.com/issues/207397158
ありがとうございます。深くて広い世界があるのですね..