21

コードの中に、置き場所を間違えていて役に立たないコメントを見つけるのは面白いと思いませんか?

コメントをほとんど書かずに、コードを理解しやすくするにはどうすればよいでしょうか?

主な方法の一つは、コードを自己文書化することです。コードが自己文書化されていれば、その働きや目的を説明するコメントは不要になり、コードの保守も非常に容易になります。

この記事では、コードを自己文書化するためのいくつかの方法を紹介します。以下は、コードを自己文書化するための3つの基本的な方法です。

  • 命名:変数や関数などの目的を名前で説明する。
  • 関数のカプセル化:特定の機能を持つコードを関数にカプセル化して、目的を明確にする。
  • 変数の導入:式を専用の変数に代入する。

これは簡単そうに見えるかもしれませんが、実際に行うと少し厄介に感じることがあります。まず、どこに問題があるのか、どこにこれらの方法が適用できるのかを理解する必要があります。

さらに、上記の3つ以外にも、広く使われている方法がいくつかあります:

  • クラスとモジュールのインターフェース:クラスとモジュール内の関数を公開して、コードをより明確にします。
  • コードのグループ化:グループを使用して、異なるコード片を区別します。

次に、実際の例を通して、上記の5つの方法を実際の応用でどのように使うかを具体的に説明します。

一、命名

まず、命名を利用してコードを明確かつ自己文書化する例をいくつか見てみましょう。

1、関数の名前変更

関数に名前を付けるのはそれほど難しくありません。以下のルールに従うことができます:

  • 「handle」や「manage」のような曖昧な言葉を避けます——handleLinks、manageObjectsなど。
  • 能動的な動詞を使用します——cutGrass、sendFileなど。関数が能動的に実行されることを示します。
  • 戻り値の型を指定します——getMagicBullet、READFILE。強い型付けの言語では、型識別子を使って関数の戻り値の型を示すこともできます。

2、変数の名前変更

  • 単位を指定します——数値パラメータがある場合は、その単位を追加できます。例えば、widthの代わりにwidthPxを使って、幅の単位がピクセルであることを指定します。
  • 簡略名は使わない——aやbはパラメータ名にできません。

二、関数のカプセル化

次に、コードを関数にカプセル化する例をいくつか見てみましょう。関数をカプセル化する利点の一つは、コードの重複を避けること、またはコード構造を改善することです。

1、コードを関数にカプセル化する

これは最も基本的です:コードを関数にカプセル化して目的を明確にします。次のコードの行が何をするのか当ててみてください:

var width = (value - 0.5) * 16;

あまり明確ではないようです。もちろんコメントがあればはっきりしますが、関数にカプセル化すれば自己文書化を実現できます……

var width = emToPixels(value);
 
function emToPixels(ems) {
    return (ems - 0.5) * 16;
}

唯一変わったのは、計算プロセスが関数に移されたことです。その関数名が何をするかを明確に示しているため、コメントを書く必要がありません。さらに、必要があれば後でこの関数を直接呼び出すこともでき、一石二鳥で重複作業を減らせます。

2、条件式の代わりに関数を使う

if文に複数のオペランドが含まれる場合、コメントを書かなければ理解するのが難しくなります。

if(!el.offsetWidth || !el.offsetHeight) {
}

上記のコードの目的が分かりますか?

function isVisible(el) {
    return el.offsetWidth && el.offsetHeight;
}
 
if(!isVisible(el)) {
}

三、変数の導入

最後に、変数の導入について説明します。上記の2つの方法に比べると、これはそれほど有用ではないかもしれませんが、いずれにしても知っている方が知らないよりはましです。

1、式の代わりに変数を使う

この例を見てください

if(!el.offsetWidth || !el.offsetHeight) {
}

今回は関数にカプセル化せず、変数を導入して置き換えます。

var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
}

2、方程式の代わりに変数を使う

複雑な式を明確に説明するためにも使用できます:

return a * b + (c / d);

変数を使って置き換えます

var divisor = c / d;
var multiplier = a * b;
return multiplier + divisor;

四、クラスとモジュールのインターフェース

クラスとモジュールのインターフェース——つまり公開されたメソッドとプロパティ——は、使用方法を説明するドキュメントのようなものです。

次の例を見てください:

class Box {
    public function setState(state) {
        this.state = state;
    }
 
    public function getState() {
        return this.state;
    }
}

このクラスは他のコードを含むこともできます。この例を挙げたのは、公開インターフェースがどのように自己文書化されるかを説明したいからです。

このクラスがどのように呼び出されるか分かりますか?明らかに、これは明確ではありません。

これらの2つの関数には、その目的を表す適切な名前を付けるべきです。しかし、そうしたとしても、使用方法はあまり明確ではありません。その場合は、より多くのコードを読むか、ドキュメントを参照する必要があります。

しかし、このように変更したらどうでしょうか……

class Box {
    public function open() {
        this.state = open;
    }
 
    public function close() {
        this.state = closed;
    }
 
    public function isOpen() {
        return this.state == open;
    }
}

かなり明確になりましたか?注意:公開インターフェースを変更しただけで、その内部表現は元のthis.stateの状態と同じです。

五、コードのグループ化

グループを使って異なるコード片を区別することも、自己文書化の一形態です。例えば、この記事で述べられているように、変数は使用する場所の近くで定義し、可能な限り変数を分類するべきです。また、これによって異なるコードグループ間の関係を示すこともでき、他の人がどのコードグループをさらに理解する必要があるかを把握しやすくなります。

次の例を見てください:

var foo = 1;
 
blah()
xyz();
 
bar(foo);
baz(1337);
quux(foo);

以下のものと比較してください:

var foo = 1;
bar(foo);
quux(foo);
 
blah()
xyz();
 
baz(1337);

fooのすべての使用をまとめて配置することで、一目でさまざまな関係が分かります。しかし、間に他の関数を呼び出さなければならないこともあります。したがって、可能であればコードのグループ化を活用し、不可能であれば無理にしないでください。

六、その他の提案

  • 奇妙な記法を使用しないでください。次の2つは同等です。
imTricky && doMagic();
if(imTricky) {
    doMagic();
}

明らかに後者の方が良いです。構文のトリックは何の利点ももたらしません。

  • 定数に名前を付ける:コード内に特別な値がある場合は、それに名前を付けるのが最善です。var PURPOSE_OF_LIFE = 42;
  • ルールを制定する:同じ命名規則に従うのが最善です。そうすれば、読者は他のコードを参考にして、さまざまなものの意味を正確に推測できます。

出典:http://www.ido321.com/1360.html