if-elseとガード節の(個人的な?)使い分け

2021.6.19

ケースバイケースなので、あくまで一つの考え方として。

はじめに結論

対称性のある正常パターンの条件分岐 → if else

不正パターンを弾くための条件分岐 → ガード節

if-elseを使うパターン

  • 男性 or 女性
  • 成人 or 未成年
  • 小学生 or 中学生 or 高校生

のような条件が対象的で、正常パターン同士の分岐にはif elseが適している

→逆に考えれば、if elseを使う事によって、正常パターンについて分岐をしているという意思表示になる


例えば年齢ごとに飲めるドリンクを決めるような処理を考えると、

if age.over_20?
  # 成人はビールとジュース
  man.drink('beer', 'juice')
else
  # 未成年はジュース
  man.drink('juice')
end

ここでmanは成人でもOKだし、未成年でもOK。

if elseを使うことで、条件に対称性があることと、どれも正常パターンであることを表現できる。

ガード節を使うパターン

  • 入力が特殊・不正値
  • 不正なパターンの分岐

のような不正なケースを除外するための分岐にはガード節が適している。


先程のコードに、ageがnilの場合を追加してみる。

return if age.nil?

if age.over_20?
  # 成人はビールとジュース
  man.drink('beer', 'juice')
else
  # 未成年はジュース
  man.drink('juice')
end

ガード節を使うことで、不正なパターンであることを表現できる。

あえて読みづらく書くと。。。

メソッド全体をif分で括ってしまうパターン

if age.present?
  if age.over_20?
    # 成人はビールとジュース
    man.drink('beer', 'juice')
  else
    # 未成年はジュース
    man.drink('juice')
  end
end

ガード節の説明にありがちなやつ。

デメリット

  • if条件が増えるたびにネストが深くなる
  • ネスト最深部のコードを読む頃には、最初のif条件を忘れていることも
  • ageがnilの場合は、ネストの条件を判定する必要がないので、パフォーマンス的も悪い(言語による)

全部ガード節にするパターン

return if age.nil?
return man.drink('beer', 'juice') if age.over_20?
man.drink('juice')
end

コード量自体は一番短くてスッキリ見える。

デメリット

  • 不正ケース1つと、正常ケース2つの条件だが、ぱっと見は不正ケース2つ、正常ケース1つに見える
  • それか、正常ケース3パターンにも見える

最後に

ガード節はリファクタリングの第一歩としては使いやすいし、何に対しての条件分岐かを意識するとさらに良いコードを書いていけそう。

このあたりにちゃんとした解説があるので、気になる人は読んでみるといいかも。