Kotlin歴が一週間の自分が、Kotlinのコードをレビューするときに指摘していること

Kotlin歴1年くらいになったら考えは変わるかもしれないので、Kotlin歴1週間での脳のスナップショットを書き留めておきます。Qiitaとかに書くと「いや、そうじゃないだろ」みたいなのが多数派だとおもうので、とりあえず自分のブログに書いておこう。

?. は3つ以上連続使用しないほうがいいんじゃない?

fragment.arguments?.getString("title")?.toUpperCase()

気持ちはわかるけど、それだったら「nullかもしれない」を排除する方向のコードにしたほうがいい気がする。 なんとなく、本当になんとなくだけど・・・。

スコープ関数は letalso だけ使うようにしましょう & apply は使わないで下さい

HogeFragment().apply {
  argument = Bundle().apply {
    putLong("id", id)
    putString("title", title)
  }
}

よりも

HogeFragment().also { fragment ->
  fragment.argument = Bundle().also { bundle ->
    bundle.putLong("id", id)
    bundle.putString("title", title)
  }
}

のほうが可読性高い気がする。 apply は、IDEの補助がないと、どのクラスのメソッドを読んでいるかを見失う。つらい。

Rubytrytap だけで概ね行けてるんだし、Kotlinだって letalso があれば行けるでしょ?とおもっているけど、違うのかな・・・。

スコープ関数とかブロックをネストするときは it は使わない

Realm.getDefaultInstance().use {
  it.executeTransaction {
    it.where(User::class.java).equalsTo("id", userId).findFirst()?.let {
      it.name = username;
    }
  }
}

だと、it が何を指してるのかパット見でわかりにくいので、

Realm.getDefaultInstance().use { realm ->
  realm.executeTransaction { realm ->
    realm.where(User::class.java).equalsTo("id", userId).findFirst()?.let { user ->
      user.name = username;
    }
  }
}

のようにレシーバーを明記しよう。 主語のない文が連続してる文章が読みづらいのと同じで、引数がないブロックが連続してるのもつらい。

スコープ関数とかブロックは3段以上ネストしない

fun saveUserName(username: String) {
  Realm.getDefaultInstance().use { realm ->
    realm.executeTransaction { realm ->
      realm.where(User::class.java).equalsTo("id", userId).findFirst()?.let { user ->
        user.name = username;
      }
    }
  }
}

でもパット見の印象は "複雑" だ。

fun inRealmTransaction(operation: (Realm) -> Unit) {
  Realm.getDefaultInstance().use {
    it.executeTransaction(operation)
  }
}


fun saveUserName(username: String) {
  inRealmTransaction { realm ->
    realm.where(User::class.java).equalsTo("id", userId).findFirst()?.let { user ->
      user.name = username
    }
  }
}

ネストの深さはせいぜいこのくらいであって欲しい。

その拡張関数、本当に拡張関数じゃないとダメなの?

IntentとかBundleとかに独自メソッドを生やすのは、まぁなんとなくはわかる。

一方で、FragmentとかActivityにメソッドを生やすのは「それ、ベースクラスつくって継承させるのじゃだめなの?」と疑いたくなる。 本当に継承じゃだめな理由があるなら、メソッドを生やせばいいけど、その場合には↓に紹介されてるように、Interfaceでスコープを明示的に示すように実装したほうが事故るリスクは少なそう。

dev.classmethod.jp

まとめ

よくわからないなりにも、"直感的にロジックが読めない"コードはどんなにきれいなコードでも排除しようとレビューをしている。

 

ところで、Googleが絶賛布教中?のDartっていう言語だと

Effective Dart: Usage | Dart

Effective Dart: Design | Dart

みたいなベストプラクティスが公式に示されている。それよりも後発のKotlinにはこういうコンテンツってないのだろうか?