2019-03-31

if-then-elseを使うかガード節を使うかの判断基準

最初に結論から

  • 一方が正常な振る舞い、もう一方は特殊な振る舞いと考えられる場合はガード節を使う
  • 双方とも同等に正常な振る舞いと考えられる場合は、if-then-else構文を使う

詳細

ガード節の有効性

プログラムを書いていると、様々な条件が考えられ、それらを考慮したコードを書かなければならないというケースが往々にして発生するだろう。
このような場合、単純にif-else ... と条件分岐を書きつらねていくとたちまち読みづらいコードになってしまう。

読みづらくなってしまう理由の1つとして条件がネストしてしまうということがあげられる。そういったときに ガード節(Guard Clauses) は有効に機能する。

# before
def some_method
  if @cond1
    'cond1 value'
  else
    if @cond2
      'cond2 value'
    else
      if @cond3
        'cond3 value'
      else
        'normal value'
      end
    end
  end
end
# after
def some_method
  return 'cond1 value' if @cond1
  return 'cond2 value' if @cond2
  return 'cond3 value' if @cond3
  'normal value'
end

条件分岐のネストが消え、副次的効果としてコード行数も削減できた。後者の方が読みやすいということにほとんど異論は無いと思う。

どちらがよりコードの意図を伝えられるか

もし条件がそこまで深くネストしていないような場合、ガード節を使うべきだろうか?

# ガード節を使わない
def some_method
  if @cond1
    'cond1 value'
  else
    'normal value'
  end
end

# ガード節を使う
def some_method
  return 'cond1 value' if @cond1
  'normal value'
end

コード行数という観点から見ると、やはりガード節を使ったほうが良さそうに思う。しかしコードの見た目上バランスが取れているのはガード節を使わない方に見えるという意見もありそうだ。

しかし、ここで本当に考えるべきはコードの見た目や行数ではなく、それぞれの処理が正常な振る舞いなのか特殊な振る舞いなのかということだ。より抽象的には、どちらがよりコードの意図を伝えられるか を考えるということでもある。

それぞれの使いどころ

『リファクタリング:Rubyエディション』 には次のように書かれている。

「条件分岐のネストからガード節へ」のポイントは、片方を強調することである。
if-then-else構文を使う場合、if/thenの分岐先と else の分岐先には同等のウェイトを置いている。これは、両方の分岐先が同じように実行され、重要だということを読者に伝える。

それに対し、ガード節は、「これはまれなケースで、発生した場合には何かちょっとしたことを行って外に出る」ということを表している。

まとめると次のようになる

  • if-then-else構文は、それぞれの処理に同等のウェイトを置く場合に使う
  • ガード節は、特殊な条件を前段で弾き、その後の処理こそが正常な振る舞いであることを示す場合に使う

先のサンプルコードで表すと、@cond1 を満たす場合も満たさない場合も同程度に正常な振る舞いと考えられるならば次のようにする。

def some_method
  if @cond1
    'cond1 value'
  else
    'normal value'
  end
end

逆に、 @cond1 は特殊な条件でのみ満たされ、満たさないケースこそが正常な振る舞いだとする場合は次のようにする。

def some_method
  return 'cond1 value' if @cond1
  'normal value'
end

※ サンプルコードなので納得感は薄いかもしれないが、現実的にはガード節の後はもっと処理量のあるコードになると思う。

最後に

この記事は、『リファクタリング:Rubyエディション』の第9章の内容の一部を噛み砕いて説明しようと試みたものです。 興味を持った方やより詳細に知りたい方は書籍を直接読んでみるのが良いと思います。