だいぶ遅くなってしまった。。。
いつもの感じでLTしてきました。 台風の日だったので参加できるかちょっと不安でしたが、なんとかなったのでよかった!
参加の経緯
Kotlin Fest 2019の懇親会にて、Kotlin Fest Reject Conf 2019の紹介があったので参加を決めました。 Kotlin Fest 2019には一つ出してダメだったネタがあったので、ちょうど良いやと思っていたので軽い感じで参加。
リジェクトでえるてぃーしよう
— Koji Wakamiya(だぐりば) (@D_R_1009) August 24, 2019
その後はちょこちょこ資料を作りながら当日に備えていたのですが、会の当日がまさかの台風15号の直撃後になってしまいました。 会は開かれるのか、というか自分はそもそも会場に迎えるのか……などと考えながらリモートワークをしていたのを覚えています。
17時半ごろから電車移動を開始したところ、案外問題なく会場までたどり着けたのでよかったです。
会の雰囲気
Reject Confということで、肩の力が抜けたLTが多く気軽にしかし深い内容を聞けたように思います。 個人的に面白いなーと思ったのは、タケハタさんの「サーバサイドKotlinでgRPCをやってみよう」。
休憩時間に投下。本日の発表資料になります! #kotlinfest_rc
— タケハタ(竹端 尚人) (@n_takehata) September 9, 2019
サーバサイドKotlinでgRPCをやってみよう https://t.co/CHSUaHcTzo
LT内でも触れられていますが、Kotlin Fest 2019でいくつかあった”サーバーサイドKotlin + GraphQL”に対する”サーバーサイドKotlin + gRPC”! 普段はAndroidアプリを作成しているのでこれらの技術選定に関わることはないのですが、もしgRPCを使うことになったらアプリは何がよくなるのかなーと考えながら聞いてました。
paniniさんがgRPCのKotlin codeを生成するライブラリを書いているので、導入すればアプリサイドはフルKotlinで実装できる気も👀
--java_out 😇 #love_kotlin
— Panini (@panini_ja) July 2, 2019
LT内容
業務アプリを色々とKotlinに書き換え、途中で詰まったところについて話しました。 ささっと進めばいいかと思ったけれど、5分では詰め込みすぎたかもと反省。
スライドでは足りなかった箇所を補足します。
2つのインスタンス化メソッドとNonNull
例えば、下記のようなクラスがあったとします。
ケース1
public class HogeFragment extends Fragment { public static HogeFragment newInstance(Fuga fuga) {} public static HogeFragment newInstance(Fuga fuga, Piyo piyo) {} }
この時、
ケース2
public class HogeFragment extends Fragment { public static HogeFragment newInstance(@NonNull Fuga fuga) {} public static HogeFragment newInstance(Fuga fuga, Piyo piyo) {} }
や
ケース3
public class HogeFragment extends Fragment { public static HogeFragment newInstance(@Nullable Fuga fuga) {} public static HogeFragment newInstance(@NonNull Fuga fuga, @NonNull Piyo piyo) {} }
であることがあります。 (ありました)
ケース1では piyo
は引数から明らかに nullable
です。
ですが fuga
はどうでしょうか? アノテーションがついていないJavaクラスからのコンバートでは、処理を一通り追わないと non-null
とすることはできません。
ケース2が一番辛いケースとなります。 サンプルコードでは引数が2つなので違和感に気付きやすいのですが、実際のコードでは引数が3~4あることがあるためです。 この場合、かなり網羅的なテストを行わないとミスに気づくことが難しくなってしまいます。
対応は、複数のインスタンス化メソッドを持つクラスにおいては、インスタンス化時に引数とした値の利用箇所を全て確認する方針とするしかありません。
共通データクラス(神データクラス)
特にJSONのパース処理がつらいので、seald classを使ってちゃんとパースしたいクラスの形にしましょう、という話。 Swaggerなどが整備されているならば、Swaggerの通りにnon-nullとnullableを表現したデータクラスを0ベースで作った方が、早いかもしれません。
使い回されるデータクラス
「便利だから」との理由で似たインタフェースを持つAPIへのリクエストや、外部SDKからのコールバックをラップしたクラスが生成されていることがあります。 このため、複数のクラスから(特に理由もなく)利用されているクラスはnullの扱いを慎重にする必要があります。 とりわけSDKからのコールバックをラップしている場合、特定のSDKを利用した時のみクラッシュするといった、検証しにくい不具合を引き当てることがあります。
onActivityResult
Activityクラスの onActivityResult
には @NonNull
や @Nullable
アノテーションがついていません。
このため、Convert to KotlinするとNonNullの引数として定義されてしまいます。
(また、親クラスにアノテーションがついていないためAndroidStudioのlint機能で対応することもできません。)
Cross Reference: /frameworks/base/core/java/android/app/Activity.java
リネーム機能を利用してあらかじめアノテーションを付与したり、コンバート後にリネームする対応が必要となります。
特に、第3引数の Intent
がnullとなってクラッシュするケースが多いように思います。
R8
OkHttp4系やKotlin Coroutines 1.3系のために、R8対応しましょう。 Gsonからの移行がつらいです。
終わりに
息の長いプロジェクトからの知見のため、あんまり響く人はいないかもなーと思っています。 が、どなたかの助けになればいいかと思っています。おわり。