コードの説明の表現として否定を使わないだけで可読性は上がる

目次

はじめに

Himenonです。

伝えたい本質は、コードリーディング時の読み手に他の解釈の余地を与えないというところにあります。これを実現する方法として「否定を使わない」というところがわかりやすいので、これをタイトルにしています。

簡単な例で否定された状態を解釈する

例えば、

let show: boolean = false;

というコードを呼んだときに、 show: falseというのは「見せるの反対の意味なので、隠す」と思考して結果を導き出します。コード上だとこうですね。

let show: boolean = false;
let hide: boolean = !show;

変数 showだけでhideの状態を表現した場合、それを読むために思考のリソースをすこしだけ消費します。コードの量や複雑度が小さい場合は耐えられるのですが、限度があります。

否定された状態が複数の意味を持ってしまう

少し難易度を上げてみます。例えば特定のディレクトリに含まれるファイル・ディレクトリを削除するというメソッド removeを考えます。実装の interface としては次のような物があったとします。

remove(targetDir: string, onlyFile: boolean);

removeの第一引数は対象のディレクトリですが、第 2 引数は onlyFile: booleanとなっています。少し強引な解釈ですが、次のように読み取ることもできます。

remove(targetDir, true); // ファイルのみ削除
remove(targetDir, false); // ファイル以外も削除?

勘の良い人は interface の時点でお気づきかもしれませんが、falseにした時点で解釈の幅が広がってしまっています。

remove(targetDir, onlyFile: false); // ディレクトリだけ削除

と表現したいのがおそらく狙いだろうと思いつつ、だけれども onlyFileの否定は集合論的には単純に「ディレクトリだけ」にはなりません。「ファイルとディレクトリ両方」の組み合わせが残ってしまいます。ベン図で書いてみると、次のようになります。

これが可読性を下げる原因にも繋がってしまっています。無論、否定で表現することで必要十分なケースもあります。

今回のケースであれば、

remove(targetDir: string, only: "FILE" | "DIRECTORY" | "ALL");

というように、ベン図で示された領域の個数だけ明確に状態を定義するとよいでしょう。ポイントとしては状態の表現は否定で表現しないことで、境界づけられた領域を的確に表現することです。

解釈の余地を与えない否定で表現できる状態

最初に上げた show のように、open/close などは否定で表現しても大丈夫でしょう。

これをベン図で見てみると、open/close という状態の共通部分がないためです。

いわゆる互いに素という状態です。この状態であれば否定を利用して他方の状態を表現しても解釈の余地を与えないため可読性は保てるでしょう。

まとめ

さて、タイトルに戻ると「コードの説明の表現として否定を使わないだけで可読性は上がる」と伝えています。これの真意は「互いに素」であるということがわかっているのであれば読み捨ててもらって良いでしょう。一方で、状態が今後増える可能性があったり、今はまだ整理の段階であるのであれば、安易に「否定の状態」を作らないことをおすすめする、というものです。

こういた裏があることはぱっと伝わりづらいので、わかりやすい説明の仕方として「否定を使わない」を覚えておくだけでコードの可読性はあがると思います。