こんにちは、hachi8833です。
状況や好みによって異なりますが、条件分岐が二重否定の形になると、一般にコードが読みにくくなる傾向があります。
unlessはうまく使えば読みやすいコードを書くときに役立ちますが、unlessが二重否定を形成するとかえって読みにくくなることもあります。三重四重は言わずもがなですね。
🔗 unlessと||の組み合わせは避けよう
unlessの是非は好みが分かれることが多く、よく議論のネタになります。
少なくともunlessと||の組み合わせは苦情が出やすいので避けましょう。
unless obj1.blank? || obj2.blank?
言葉で書けば「obj1とobj2のどちらもblankでないなら」となります。コーディング前にこのような表現で考えるのはよくあることですが、それをそのままロジックに落としこむと上のようなコードになってしまいます。
blank?と逆のpresent?が使えるなら、ド・モルガンの法則(後述)を活用して次のように書き換えると、ぐっと目に優しいコードになります。
if obj1.present? && obj2.present?
言葉で書けば「obj1とobj2が両方とも存在すれば」となり、こちらも素直な表現になります。
🔗 not演算子!の混用は避けよう
unless条件の中でnot演算子!が使われると、二重否定が発生して読みにくくなるので、避けましょう。
unless !obj1.blank? #=> 読みにくい
if obj1.blank? #=> 読みやすい
unlessに限らず、複数条件の一部でnot演算子!が使われると「部分否定」の形になり、読みにくくなります。
blank?→present?のように、対義語メソッドに置き換えるなどして、not演算子!を含まない表現にすることで、読みやすくなります。
if obj1.blank? && !obj2.blank? #=> 読みにくい
unless obj1.blank? && !obj2.blank? #=> さらに読みにくい
if obj1.blank? && obj2.present? #=> 比較的読みやすい
🔗 参考: ド・モルガンの法則
任意の命題
に対して
が成り立つ。これをド・モルガンの法則という。
ド・モルガンの法則 - Wikipediaより
同じことをC言語のようなプログラミング言語の記号で表せば、P, Q がどんな論理式であろうと以下が成り立つということです。
!(P || Q) == !P && !Q
!(P && Q) == !P || !Q
「命題の対偶は常に元の命題と真偽が一致する」と並んで、安心して使えるロジックですね。
🔗 unlessはシンプルな場合に使おう
条件が1つで、かつelse文を使わないシンプルな条件判断であれば、unlessを使うことで視認性が向上することもあります。
unless obj1.member?
何かする
end
特に実行するコードが1行だけの場合は、後置のunlessにするのがRuboCopでも推奨されています。
Club.alert unless obj1.member?
参考: Style/IfUnlessModifier -- Style :: RuboCop Docs
🔗 unless A && Bはどうか
「unless A && Bはまだ許せるけどunless A || Bは混乱するから嫌だ」という意見が社内でいくつか出ました。
unless A || Bの場合、A || Bが成立するパターンが4つのうち3つもあり(Aだけがtrueの場合、Bだけがtrueの場合、AとBが両方ともtrueの場合)、さらにそれぞれが否定されるので、脳への負担が大きくなりそうです。
unless A && Bの場合、A && Bが成立するパターンが4つのうちで1つしかない(=AとBがtrueの場合に限る)ので、その分ましなのでしょう。
それでもunlessの複数条件は読みにくくなりやすいので、可能であればド・モルガンの法則を使ってifに書き換えることを検討してみましょう。
🔗 「場合による」という意見
対義語メソッドについては別途記事にする予定です。



更新情報