Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Koji Wakamiya
September 09, 2019

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

Koji Wakamiya

September 09, 2019
Tweet

More Decks by Koji Wakamiya

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    support lib 27.1.1のDiffUtil.ItemCallbackを、support libのpathがおかしい状態で追加した時にも同じような
    問題が発生することがある
    (28.0.0以降ではNonNull扱いとなっているため問題なし
    )
    17

    View full-size slide

  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

    View full-size slide

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

    View full-size slide