「キレイなコード」とは ――
キレイなコードを目指すべきか ――
これはエンジニアにとっての永遠の課題、Twitter をはじめ多くのエンジニアが議論を白熱させます。
私個人の意見として、「キレイなコード」の定義は重要ではなく、
新規でコードを書くときには、「ある程度の前提知識」がある人にとって、意図が理解しやすく、実際に動かしたときに予想を裏切らず「驚き」が少ない コードを書くことが大事なことであり、そのようなコードに「美しさ」を見いだせるセンスを身につけるべきだと思います。
もちろん、言語の特性もうまく理解して、「博識な人の自己満足」に陥らないように注意する必要があります。 使用するのは言語・ライブラリの標準的な機能なのか、ググって容易に浅く理解できる内容かどうか考えるのが良いと思います。
今回のテーマ
今回のテーマは、「null 結合・オプショナルチェーン演算子」です。
「〇〇が undefined でも null でもないときには、~~」という場合に、次のように書いていませんか?
// options: { [key: string]: string } | undefined
options ? options[key] ? options[key] : "default" : "default"
私はこれよりも
options?.[key] ?? "default"
のように書いたほうが良いと思っています。
(ボツ) 指摘いただきましたが、最初の版では以下のように書いていました。 こういうミスをひっくるめたフォールバックを書けるのも null 合体 / オプショナルチェーンの醍醐味ですね(苦しい言い訳)
// options: { [key: string]: string } | undefined
options ? options[key] : "default"
理由
理由は「短いほうが良いから」
...
ではありません。
コードは短ければ良いというものでもありませんし、短さを目指すあまり暗黙的すぎるコードになってしまっては、それこそ「自己満足」になってしまい元も子もありません。
私が思うに、このような利点があると思っています。
-
?.
と??
は? :
よりも用途が限定されているから -
options
を繰り返さず、文字数あたりの情報量が増えるから- 読み飛ばさないといけない文字が多いと負担になる
- フローの「幹」・「枝」の関係がはっきりするから
- ロジックの流れを「ただの条件分岐」じゃなくて「フォールバック」として捉えなおす
ひとつひとつ見ていきましょう。
1. 用途が限定された機能を使う
?.
は オプショナルチェーン と呼ばれる演算子で、非 nullish の場合には何かをして、nullish であれば何もせず undefined が結果として帰ってきます。
単なるプロパティのアクセスだけでなく、角括弧も使えますし、nullable な関数の呼び出しにも使うことができます。
ご存知でない方は是非おぼえて帰ってください。
// プロパティのアクセス
object?.hoge
// 角括弧を使ったアクセス
object?.["hoge"]
// 関数の呼び出し
nullableFn?.()
??
は ヌル合体演算子 という名前で、左辺の値が nullish であれば代わりに右辺の値を結果として返す演算子です。
オプショナルチェーン、ヌル合体演算子は、どちらも「nullish かどうか」で分岐が起こるのが特徴です。 &&
||
object ? t : f
のような論理演算子・三項演算子は「偽値かどうか」で分岐が起こります。
後者を扱うと、nullish 以外の偽値 (false, 0, "", document.all など) が入ってくる可能性がノイズとしてコードを読解時に邪魔しますが、前者を使うことで、そのノイズを気にする必要がなくなります。
しかも、慣れてくると ?.
や ??
という記号を見ただけで「これは nullish のときにフォールバックするコードだ」と理解できるようになります。
2. 読み飛ばさないといけない文字を減らす ―― 文字数あたりの情報量
もう一度 before と after のコードを見比べてみましょう。
// before
options ? options[key] ? options[key] : "default" : "default"
// after
options?.[key] ?? "default"
もし、チェーンが長くなると、
// object.hoge が nullable だったら
object.hoge?.[key] ?? "default"
object.hoge ? options.hoge[key] ? options.hoge[key] : "default" : "default"
のように、読む意味の薄い、繰り返される「主語」の部分が長くなっていきます。
読み飛ばさないといけない文字の存在が 文字数あたりの情報量 を減少させ、コードの読解を難しくしてしまっています。
3. フォールバック ―― フローの幹と枝を意識する
条件分岐(および三項演算子)を使っていたときには、処理の流れ・フローが「二股の分岐」 になっていました。(しかも、↑のように、 nullable な箇所が増えるたびに分岐の数が増えていきます。)
しかし、null結合・オプショナルチェーン演算子に置き換えることによって、
- 「一つも nullish に引っかからなかった場合」という「幹」
- 正常系
- 「一つでも nullish があった場合」という「枝」
- 異常系
- フォールバック
としてフローを捉え直すことができます。
この「条件分岐を "幹と枝" で捉え直す」という考え方は他のテクニックにも関連しまているので、次回はこの「フローの幹と枝」に注目してみようと思います。
▼ つづきの記事はこちらです。