JavaからKotlinに書き換えてハマる話

494a2760dceccc31c4bcdb689041c614?s=47 Koji Wakamiya
September 09, 2019

 JavaからKotlinに書き換えてハマる話

494a2760dceccc31c4bcdb689041c614?s=128

Koji Wakamiya

September 09, 2019
Tweet

Transcript

  1. JavaからKotlinに 書き換えてハマる話 Kotlin Fest Reject Conference 2019 [非公式]@DeNA

  2. 自己紹介 Name : Koji Wakamiya Work : Studyplus, inc. Github

    : @koji-1009 Twitter : @D_R_1009 Blog : https://blog.dr1009.com/ Kotlin歴は2年ちょっと 2
  3. MISSION 「学ぶ喜びをすべての人へ」 多くの人がStudyplusを通じて学習のきっかけを見つけ、 学習を楽しく継続できることを実現する。 3

  4. StudyplusアプリのKotlin化 • コミット履歴によると2017年12月ごろにKotlinを追加 ◦ 当時のminSDKは15 ◦ 2019年9月現在は21 • 話者がスタディプラスに参加したのは2018年9月 ◦

    本日の話は2018年9月から2019年9月に体験した物事がベースになってます 4
  5. JavaからKotlinへの書き換え状況 • 2018年7月末 ◦ Java : 75,000行 ◦ Kotlin :

    20,000行 5
  6. JavaからKotlinへの書き換え状況 • 2019年8月末 ◦ Java : 19,000行 ◦ Kotlin :

    72,000行 6
  7. JavaからKotlinへの書き換え状況 • 2019年9月9日(本日) ◦ Java : 15,000行 ◦ Kotlin :

    74,000行 7
  8. JavaからKotlinへの書き換え状況 8 2018年7月 2019年8月末 2019年9月9日

  9. お品書き • 2つのインスタンス化メソッドと NonNull • 共通データクラス(神データクラス) • 使い回されるデータクラス • onActivityResult

    • R8 9
  10. 2つのインスタンス化メソッドとNonNull 状況: AFragment.newInstance(Hoge hoge); AFragment.newInstance(Hoge hoge, Fuga fuga); 問題: 1.

    hogeがNonNull/Nullableのケースが存在する 2. fugaをNonNullとして扱わなければならないが、 レアケースでしか利用されない 10
  11. 2つのインスタンス化メソッドとNonNull 防ぐためには?: 1. インスタンス化メソッドの引数は必ずクラス内の利用箇所全てを確認する 2. lateinit varによる対応は市場クラッシュを引き起こすので、 valの利用を必ず検討する 11

  12. 共通データクラス(神データクラス) 状況: 1. 複数のSNS連携完了を伝えるデータクラスが 1つにまとめられている 2. 複数の型要素があるJsonをパースするため、 全要素を持つ1つのデータクラスが作成されている 問題: 1.

    防御的にNullableで宣言して、動作を見ながら確認する必要が生じる 2. GsonからMoshiへ移行した際に、JsonDataExceptionの恐れがある 12
  13. 共通データクラス(神データクラス) 防ぐためには?: 1. @NonNull/@Nullableアノテーションをデータクラスにつける 2. 抽象クラスを利用するなど、全部入りクラス作成を避ける 13

  14. 使い回されるデータクラス 状況: 複数のビジネスロジックがデータクラスを使いまわした結果、 複数のコンストラクタがあるデータクラスが作成されていた 問題: 1. 複数のクラスに応じたプロパティ追加の結果、 NonNullの保証がない 2. 複数のコンストラクタが存在する

    14
  15. 使い回されるデータクラス どう対応するか: 基本的にKotlin Data Classの利用を行うが、いくつかアプローチがある 1. secondary constructorを利用する 2. 利用クラスをKotlin化し、名前付き引数を利用する

    3. Java + @JvmOverloadsの利用も可能だが、 引数のパターンによっては単に複雑性をますため注意 15
  16. onActivityResult 状況: onActivityResult処理が含まれているActivityをKotlin化したところ、 dataがnullのケースでクラッシュが発生 問題: 1. onActivityResultは古いAPIのためアノテーションが付与されていない 2. Nullableな値をNonNullとしてメソッドをoverrideしても、 エラーは発生しない

    16
  17. onActivityResult どう対応するか: 1. あらかじめJavaのonActivityResultメソッドを アノテーション付きのメソッドに書き換えてから Kotlin化する 2. Kotlin化されたコードのonActivityResultメソッドを 置換機能で全て修正する ※

    support lib 27.1.1のDiffUtil.ItemCallbackを、support libのpathがおかしい状態で追加した時にも同じような 問題が発生することがある (28.0.0以降ではNonNull扱いとなっているため問題なし ) 17
  18. R8 状況: R8対応が必要になるケースが増えた (AGP3.4以上でデフォルト有効化、 Kotlin Coroutines 1.3系やOkHttp4系などのビルドクラッシュ) 問題: 1. Gson使っていると(そのままでは)ダメ

    a. https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md b. ビルド時ではなく実行時に問題が見つかるため、発見が難しい 18
  19. R8 どう対応するか: 0. 対応しない(各種ライブラリ対応を待つ) 1. .proファイルの指定を頑張る 2. データクラスのKotlin化 + Moshi-Codegenへ移行する

    ※なおKotlin Coroutinesを利用している場合には、 Dispatchers.Main初期化遅延問題のためR8移行が望ましい 19