1. 序章

このチュートリアルでは、コメントについて説明します。 2つのカテゴリーを紹介します。 次に、いくつかの適切な例と不適切な例を見ていきます。 最初に、代替案についても見ていきます。

2. 他の種類

コメントを使用する最初の理由は、APIを文書化することです。 JavaではJavadocと呼ばれ、PHP DocblockではC#では「XMLドキュメントコメント」と呼ばれます。

それらはAPIの使用方法を説明します。 APIのユーザーがソースコードにアクセスできない可能性があることを認識しておく必要があります。 したがって、ドキュメントには、予想される入力と出力が記載されています。 また、ユーザーが予期する必要のある例外とエラーについても説明する必要があります。 ドキュメントは、明確で、完全で、明確である必要があります。

他のコメントは私たちのプロジェクトの開発者に焦点を当てています。 たとえば、開発の決定について説明します。 または、将来のバージョンで修正する必要がある問題を文書化します。 この記事の残りの部分では、開発者向けの内部コメントに焦点を当てます。

3. 目標

前のセクションでは、コメントが開発者を対象としていることをすでに強調しました。 通常の商業プロジェクトの場合、これには、その存続期間中の幅広い個人が含まれる可能性があります。 つまり、ジュニア開発者から非常に経験豊富な開発者、そして異なる文化的背景を持つ人々です。 コメントを書くときは、常にそのことを念頭に置いておく必要があります。

理想的には、コードは自明であり、コメントすら必要ありません。 ただし、コードだけで何かを表現できない場合があります。コメントと正規表現を含む次のフラグメントを参照してください。

// Matches a Dutch zipcode, eg, '1974 XA' or '4844RA'
Pattern DUTCH_ZIPCODE = Pattern.compile("[1-9][0-9]{3} ?[A-Z]{2}");

コメントがなくても、正規表現の経験がある開発者やオランダの人々にとって、正規表現は明確です。 ただし、フランスのジュニア開発者にとって、この正規表現はこのコメントの方が理にかなっています。

4. 欠点

コメントは、ほとんどの場合、書かれているときに正しいです。 ただし、コードは動的であり、遅かれ早かれコードが変更される可能性があります。 ビジネスロジックが変更されたため、コードが変更される可能性があります。 ただし、テストではコメントは検証されません。 それらも更新しましたか? コメントをコードと一緒に移動しましたか? または、コメントは孤立しましたか?

したがって、最大の欠点は、コメントが常にコードに続く傾向があるとは限らないことです。 時々人々はコードとそのコメントの間に新しいコードを置くかもしれません。 コードを変更してコメントを更新するのを忘れることがあります。 そのため、コメントは私たちを誤解させ始める可能性があります。

もう1つの問題は、多くのプロジェクトにコメントが必要なガイドラインがあることです。 ただし、有益でないコメントがあると、脳がそれらを除外するように訓練されるだけです。したがって、必要なときにそれらのコメントを更新できないリスクが高まります。

これらの欠点があるため、コメントよりも自明のコードを常に優先する必要があります。 その場合、コメントは例外になる可能性があります。 そして、彼らがいるとき、私たちは彼らを最新の状態に保つことを覚えているかもしれません。

5. 不適切な使用法

どのコメントが有用でどれが役に立たないかについて、さまざまな人々が異なる意見を持っています。 あまり役に立たないと一般的に認められているコメントをグループ化するために最善を尽くしました。 また、いくつかの代替案についても説明します。

5.1. 明白なことを述べます

不要なコメントの良い例は、明白なことを述べることです。 次のフラグメントを見てみましょう。

// numeric session-id
int sessionId = 0;
 
// expiry date
Date expiry = new Date();

上記のコメントは明白であり、省略したほうがよいかもしれません。

ただし、次のフラグメントのコメントはより危険です。

// numeric session-id
int sessionTimeoutInSeconds = 3600;

前の例の1行目からコピーした可能性があります。 ただし、更新に失敗したため、コメントは実際の情報やコンテキストではなく混乱をもたらすようになりました。

最後に、例のコメントは、コードが何をしているのかを説明しています。

// resets session-id to 99;
function reset() {
    sessionId = 99;
}

ただし、コメントなしでも理解できます。 また、更新するときにコメントを更新するのを忘れてしまう可能性があるため、そのコメントを書かない方がよいでしょう。

5.2. 不明確なコードの説明

以前、私たちは自明のコードを好むことをすでに議論しました。 たとえば、変数とメソッドに適切に選択された名前を使用します。 または、コードを適切な名前の変数またはメソッドに抽出して、読みやすくします。 たとえば、私たちがかつてレビューしたこのコードの断片を参照してください。

int timeout = 5; // timeout in seconds

残念ながら、コメントはこの行にのみ表示され、変数が使用されている場所には表示されません。 名前を更新すると、コメントを削除して、このタイムアウトを使用するすべての場所でユニットを明確にすることができます。

int timeoutInSeconds = 5;

場合によっては、複雑なifステートメントを次のように文書化することもあります。

// if during work hours
if (currentTime.hours >= 9 && currentTime.hours <= 17)

このコードを少し書き直すと、コードの可読性が向上し、コメントが廃止される可能性があります。

if (isDuringWorkingHours(currentTime))

コードを少し改善すると、コメントが陳腐化することがあります。 また、同時にコードの可読性を向上させます。

5.3. バージョン管理システムの活用の失敗

バージョン管理システム(git、SVN、CVSなどのVCS)の現在の使用法では、例のグループが廃止されています。

// MvW 2020-08-20 Added method to validate working hours
function isDuringWorkingHours() {
...
}

// code below became obsolete on 2020-08-20
// function isAfterWorkingHours() {
// ...
// }

VCSは、上記のすべての例を追跡します。 むしろ古いコードを削除する必要があります。 また、ソースファイルの履歴を追跡する理由はありません。適切なコミットメッセージを使用するようにしてください。

いくつかの例と可能な改善点を検討しました。 次のセクションでは、コメントの適切な使用法をいくつか提案します。

6. 適切な使用法

前のセクションでは、プログラミング言語だけでは自分自身を表現するのに十分でない場合にコメントを使用する必要があることを説明しました。 次のセクションでは、言語自体だけでは表現できないシナリオをいくつか見ていきます。

6.1. 法的義務

法的な理由から、すべてのファイルの前に著作権ヘッダーを付けることが望ましい場合があります。 これが必要または望まれる場合、それを含めない理由はまったくありません。 また、このコメントが実際のコードロジックにリンクされていないという利点もあります。 コードの更新中にそれを更新する必要はなく、私たちの脳はそれをフィルターで取り除く可能性があります。 ほとんどの場合、IDEによっても非表示になります。

6.2. タスクまたは既知の欠陥に注釈を付ける

何かを変える必要があることを知っていることもありますが、それを行う時間はまだありません。 次に、TODOまたはFIXMEコメントを追加するのが理にかなっています。 これにより、保留中のタスクがあることが他の人に明確になります 。 そして、私たちのIDEは、それらすべてを追跡して一覧表示できる可能性があります。 ただし、JIRAなどの課題追跡システムをプロジェクトに使用する場合は、常にコメントをバックログのタスクにリンクすることを目指す必要があります。

// FIXME CS-122 the method below fails in leap years
function isAfterWorkingHours() {
    ...
}

6.3. 重要なコード

以前に紹介したように、開発者はさまざまな経験レベルを持つことができます。 したがって、正規表現や日付パーサーなどのより複雑なコード構造を使用する場合。 意図された動作を説明することは理にかなっています。

例として、セクション3で示した正規表現の説明があります。 また、そのような説明はコードレビュー中に大いに役立つことに注意してください。 ただし、説明がロジックと一致していることを確認する必要があります。

6.4. 理由の説明

非常に便利なタイプのコメントは、コードがどのようになっているのかを説明しています。 明確な命名だけでは不十分な場合があり、コンテキストが本当に必要です

int resultCode = ...;
boolean isSucess = resultCode == 200;
boolean isTemporaryError = resultCode == 503 || resultCode == 504;
// Sometime we receive a temporary error. 
// However, in all cases which were researched, results were successfully stored.
// Because of this we will return true in that case.
return (isSucess || isTemporaryError);

これらのコメントも警告である可能性があります。コードが間違っているか、簡単に改善できる可能性があるためです。 ただし、クラスはスレッドセーフではない可能性があり、フィールドを変数に抽出するとアプリケーションが破損します。 または、ユーザーが問題に直面したために回避策が展開された可能性があります。 具体的な例としては、影響が直接示されないため、複数回(再)導入された問題が考えられます。

// Don't rewrite this to try-with-resources because that will
// auto-close the socket. The socket is needed every 15 minutes so the 
// error might not show directly but this will break the application
try {
    ... open a socket
} catch (IOException e) {
    ... handle error
}

7. 結論

この記事では、さまざまなコメントの例を見ていきました。 避けるべきいくつかの例と、コメントが最善の解決策である他のいくつかの例を検討しました。

最も重要なポイントは、役立つコメントを追加するだけで、コメントを最新の状態に保つのが簡単になる可能性があるということです。