Ruby

【Ruby】乱用厳禁!?後置ifで書くとかえって読みづらくなるケース

はじめに

Rubyではif文を後置if(if修飾子)を使って1行で書き直すことができます。

# 普通のif文
if foo
  bar
end

# 後置ifを使ったif文
bar if foo

ただし、後置ifが使えるからといって、無理に普通のif文を後置ifに書き直す必要はありません。
むしろ、後置ifを使うとかえって読みづらくなるケースもあります。

後置ifが不向きなケース

たとえば、あなたがコードレビューをしているとき、こんな(物騒な)コードを見かけたらどう思いますか?

Screen Shot 2018-08-31 at 8.20.08.png

「おいおい、頭大丈夫?」と思うようなコードですが、実はこのコードは後置ifで書かれていました。
(ユーザがゾンビだった場合のみ、メッセージを返すメソッドだった!)

Screen Shot 2018-08-31 at 8.21.31.png

後置ifを読むときは条件文があとにやって来ます。
コードが横に長いと条件文がぱっと目に入らないため、「えっ、なんでこのタイミングでこんな処理が入るの!?」と読み手を困惑させる原因になります。

こういったケースでは普通のif文で書いた方が可読性が高くなります。

def message_to(user)
  # 普通のif文で書けば、特定の条件のみメッセージを返すことは明らか
  if user.zombie?
    '絶対ぶっ○す!絶対ぶっ○す!絶対ぶっ○す!絶対ぶっ○す!絶対ぶっ○す!絶対ぶっ○す!'
  end
end

もちろん、ここで挙げた例は少し極端ですが、読み手は「上から下へ」「左から右へ」コードを読んでいくことを考えると、後置ifは可読性を悪化させる一因になることが想像できるのではないでしょうか。

後置ifが向いているケース(主観)

個人的には後置ifはあまり多用すべきではないと考えています。
僕がRubyのコードを書くときは単純に「後置ifに直せるかどうか」にかかわらず、「これは後置ifで書いた方がシンプルでわかりやすい」と思う場合のみ、後置ifを使うようにしています。

具体的には次のようなケースです。

  • 後置ifを使っても横に長くならない
  • 自然な英語っぽく読める(「do A if B = BならAせよ」の形式で読める)

後置ifが特に便利なのは、ガード節をシンプルに書きたいときですね。

def go_to_school
  # 眠かったら通学しない(処理中止)
  return if sleepy?

  get_up
  eat_breakfast
  leave_house
end

returnの代わりに例外を発生させて処理を中断するコードに使うのもいいと思います。

def buy(item)
  # お金がなければ買えないので例外を発生させて中断する
  raise TooPoorError if no_money?

  self.money -= item.price
end

もちろん、ガード節以外のときに使うのもありです。
以下のようなコードは「英語っぽく読める」という条件には合致しないかもしれませんが、「横に長くならない」という条件は満たしているのでOKだと思います。

price = item.price
# 特売日なら10円引き
price -= 10 if special_day?
price

前述のとおり、横に長くなったり、凝ったコードを書いたりする場合は、普通のif文を使いましょう。

price = item.price
if special_day?
  # 横に長くなったり、凝ったコードを書いたりする場合は後置ifを避ける
  price = calc_special_price(price) { |rate| rate * item.rate_adjustment }
end
price

おまけ:後置ifを使わずに同等の処理を1行で書く方法

if + then + end で1行に書く方法もあります。
ただし、英文っぽく読むにはendがちょっと邪魔な気がしますね。

# もし金を持っていなければ処理中止
if no_money? then raise TooPoorError end

こちらはand演算子でつなげる書き方です。
ただ、こういう書き方(イディオム)に馴染みがないと、何をやっているのか一見わかりづらいかもしれません。

# 金なしか?それなら処理中止
no_money? and raise TooPoorError

or演算子を使って「A? or B = Aか?さもなければBせよ」という書き方もあります。(Perl風)

# 金を持っているか?さもなければ処理中止
has_money? or raise TooPoorError

このようにいくつかのバリエーションはありますが、個人的には後置ifが一番スッキリしていて好きです。

# 個人的にはこれがベスト!
raise TooPoorError if no_money?

まとめ

というわけで、この記事では後置ifの向き不向きについて考えてみました。
もちろん、これはあくまで僕個人の主観なのでまったく強制力はありません。

ですが、今まであまり深く考えずに後置ifを多用してきた人は、後置ifのせいでコードの可読性が落ちていないか、これから少し注意するようにしてみてください :smiley: