Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

自己紹介 Name : Koji Wakamiya Work : Studyplus, inc. Github : @koji-1009 Twitter : @D_R_1009 Blog : https://blog.dr1009.com/ Kotlin歴は2年ちょっと 2

Slide 3

Slide 3 text

MISSION 「学ぶ喜びをすべての人へ」 多くの人がStudyplusを通じて学習のきっかけを見つけ、 学習を楽しく継続できることを実現する。 3

Slide 4

Slide 4 text

StudyplusアプリのKotlin化 ● コミット履歴によると2017年12月ごろにKotlinを追加 ○ 当時のminSDKは15 ○ 2019年9月現在は21 ● 話者がスタディプラスに参加したのは2018年9月 ○ 本日の話は2018年9月から2019年9月に体験した物事がベースになってます 4

Slide 5

Slide 5 text

JavaからKotlinへの書き換え状況 ● 2018年7月末 ○ Java : 75,000行 ○ Kotlin : 20,000行 5

Slide 6

Slide 6 text

JavaからKotlinへの書き換え状況 ● 2019年8月末 ○ Java : 19,000行 ○ Kotlin : 72,000行 6

Slide 7

Slide 7 text

JavaからKotlinへの書き換え状況 ● 2019年9月9日(本日) ○ Java : 15,000行 ○ Kotlin : 74,000行 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

2つのインスタンス化メソッドとNonNull 状況: AFragment.newInstance(Hoge hoge); AFragment.newInstance(Hoge hoge, Fuga fuga); 問題: 1. hogeがNonNull/Nullableのケースが存在する 2. fugaをNonNullとして扱わなければならないが、 レアケースでしか利用されない 10

Slide 11

Slide 11 text

2つのインスタンス化メソッドとNonNull 防ぐためには?: 1. インスタンス化メソッドの引数は必ずクラス内の利用箇所全てを確認する 2. lateinit varによる対応は市場クラッシュを引き起こすので、 valの利用を必ず検討する 11

Slide 12

Slide 12 text

共通データクラス(神データクラス) 状況: 1. 複数のSNS連携完了を伝えるデータクラスが 1つにまとめられている 2. 複数の型要素があるJsonをパースするため、 全要素を持つ1つのデータクラスが作成されている 問題: 1. 防御的にNullableで宣言して、動作を見ながら確認する必要が生じる 2. GsonからMoshiへ移行した際に、JsonDataExceptionの恐れがある 12

Slide 13

Slide 13 text

共通データクラス(神データクラス) 防ぐためには?: 1. @NonNull/@Nullableアノテーションをデータクラスにつける 2. 抽象クラスを利用するなど、全部入りクラス作成を避ける 13

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

使い回されるデータクラス どう対応するか: 基本的にKotlin Data Classの利用を行うが、いくつかアプローチがある 1. secondary constructorを利用する 2. 利用クラスをKotlin化し、名前付き引数を利用する 3. Java + @JvmOverloadsの利用も可能だが、 引数のパターンによっては単に複雑性をますため注意 15

Slide 16

Slide 16 text

onActivityResult 状況: onActivityResult処理が含まれているActivityをKotlin化したところ、 dataがnullのケースでクラッシュが発生 問題: 1. onActivityResultは古いAPIのためアノテーションが付与されていない 2. Nullableな値をNonNullとしてメソッドをoverrideしても、 エラーは発生しない 16

Slide 17

Slide 17 text

onActivityResult どう対応するか: 1. あらかじめJavaのonActivityResultメソッドを アノテーション付きのメソッドに書き換えてから Kotlin化する 2. Kotlin化されたコードのonActivityResultメソッドを 置換機能で全て修正する ※ support lib 27.1.1のDiffUtil.ItemCallbackを、support libのpathがおかしい状態で追加した時にも同じような 問題が発生することがある (28.0.0以降ではNonNull扱いとなっているため問題なし ) 17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

R8 どう対応するか: 0. 対応しない(各種ライブラリ対応を待つ) 1. .proファイルの指定を頑張る 2. データクラスのKotlin化 + Moshi-Codegenへ移行する ※なおKotlin Coroutinesを利用している場合には、 Dispatchers.Main初期化遅延問題のためR8移行が望ましい 19