コードを書いている時や、同僚のコードレビューをしている時に、複雑な条件文に出くわすことがあります。もうちょっと簡単に書けそうな気はするけど、具体的にどうしたら良いかわからないとか、書き直したものが同じ挙動になるかわからなくて不安なのでそのまま放置してしまったということは、エンジニアなら誰でもあると思います。
そういった場合に私がよく使うのが、「ド・モルガンの法則」です。オーガスタス・ド・モルガンという数学者が発見した論理学の法則なのでそう呼ばれています。
この法則は2つの部分に分かれており、それぞれ以下のように定義されます。
1. (A OR B)の否定は、Aの否定 AND Bの否定と同義である。
rubyで書くと以下のようになります。
!(A || B) == !A && !B
2. (A && B)の否定は、Aの否定 OR Bの否定と同義である。
rubyで書くと以下のようになります。
!(A && B) == !A || !B
要は、ORをANDで表現するとどうなるか(もしくはその逆)を教えてくれるわけです。
定義だけだとわかりにくいので、実際のコードの例でどのように使われるかを見てみましょう。
Ruby on Railsで例を上げると、以下のようなコードがあったとします。
unless variable_1.blank? && !boolean_method?
なんだかunlessと否定が組み合わさって読みにくいですよね。
あくまで一般論ですが、否定がたくさんあると「この反対の意味は」と脳内で変換する手間が増え、読みにくいと感じることが多くなります。
この条件文の実行結果は同じに保ちつつ、シンプルにして可読性をあげれないか試してみます。
まず、unlessはif !と同じ意味なので置き換えます。
if !(variable_1.blank? && !boolean_method?)
さらに、ド・モルガンの法則の定義に当てはまるように、blank?を対義語メソッドのpresent?に置き換えて冒頭に否定(!)を追加します。
if !(!variable_1.present? && !boolean_method?)
これで、ド・モルガンの法則の1つめの定義に登場する、!A && !B の形になりました。
!A && !Bはド・モルガンの法則によると!(A || B)と同じ意味なので、以下のように変形することができます。
if !!(variable_1.present? || boolean_method?)
最後にifの後のダブル否定がお互いに打ち消しあって、以下の通りとなります。
if variable_1.present? || boolean_method?
これで、最初のunlessと否定が混じった条件文と比べてずいぶん読みやすくなりましたね。
もう1つ、今度はrubyではなくSQLでの例を記載します。
以下のようなWHERE句があったとします。
WHERE column_a != 'foo' OR column_b != 'bar'
これはド・モルガンの法則の!A || !Bに当てはまりますので、ANDに変換が可能です。
WHERE NOT(column_a = 'foo' AND column_b = 'bar')
どちらのSQLが読みやすいかはコンテクストによるかと思いますが、SQLが直感的に理解出来なくて変換してみたらすんなり頭に入ってきた、ということは私の経験ではよくあります。
まとめ
このように、コーディングでは「AND」と「OR」を入れ替えることで「否定」を使わなくて良くなり、可読性が向上する場合が多々あります。読みにくい条件文に出会った時にド・モルガンの法則を知っていると、同じ実行結果を担保しながらもっと読みやすく変換できるな、と思えるようになるので、ぜひ覚えてみてください。
