こんにちは、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
に書き換えることを検討してみましょう。
🔗 「場合による」という意見
対義語メソッドについては別途記事にする予定です。
更新情報