web-dev-qa-db-ja.com

複雑なコードを説明するコメントの何が問題になっていますか?

多くの人々は、「コメントは「なぜ」ではなく「なぜ」を説明すべきである」と主張しています。他の人は、「コードは自己文書化されるべきである」とコメントし、コメントは不足しているべきです。ロバートC.マーティンは、(自分の言葉に言い換えると)「コメントは不適切に書かれたコードに対する謝罪である」としばしば主張しています。

私の質問は次のとおりです:

複雑なアルゴリズムまたは長く複雑なコードを説明コメントで説明することの何が問題になっていますか?

このようにして、他の開発者(自分を含む)がアルゴリズム全体を1行ずつ読み取ってその内容を理解する代わりに、平易な英語で書いたわかりやすい説明コメントを読むだけで済みます。

英語は人間が理解しやすいように「デザイン」されています。 Java、RubyまたはPerl)は、人間の読みやすさとコンピュータの読みやすさのバランスをとるために設計されているため、テキストの人間の読みやすさが損なわれます。人間は英語の部分をはるかに速く理解できます彼/彼女は同じ操作でコードの一部を理解できること(操作が簡単でない限り)。

それでは、部分的に人間が読めるプログラミング言語で書かれた複雑なコードを書いた後、フレンドリーで理解しやすい英語でコードの操作を説明する簡潔で簡潔なコメントを追加してみませんか?

「コードを理解するのは難しいことではない」、「関数を小さくする」、「わかりやすい名前を使用する」、「スパゲッティコードを書かない」と言う人もいます。

しかし、それで十分ではないことは誰でも知っています。これらは単なるガイドライン-重要で有用なもの-ですが、一部のアルゴリズムが複雑であるという事実を変更するものではありません。したがって、1行ずつ読み取ると理解が困難です。

一般的な操作についての数行のコメントで複雑なアルゴリズムを説明するのは本当に悪いことですか?コメントで複雑なコードを説明することの何が問題になっていますか?

241
Aviv Cohn

簡単に言えば:

  • コメントに問題はありません自体があります。何が問題なのかというと、そのようなコメントを必要とするコードを書くか、わかりやすい英語でわかりやすく説明している限り、複雑なコードを書いても大丈夫だと考えていることです。
  • コードを変更しても、コメントは自動的に更新されません。そのため、コメントがコードと同期しないことがよくあります。
  • コメントはコードのテストを容易にしません。
  • 謝罪は悪くない。あなたが謝罪する必要があること(簡単に理解できないコードを書くこと)は悪いことです。
  • 複雑な問題を解決するために単純なコードを書くことができるプログラマーは、複雑なコードを書いてから、彼のコードが何をするかを説明する長いコメントを書くプログラマーよりも優れています。

最終行:

自分を説明することは良いことであり、そうする必要はない方が良いです。

410

コードが複雑になったり混乱したりする理由はたくさんあります。 最も一般的なの理由は、コードをリファクタリングして混乱を少なくすることで対処できます。コメントを追加するのではありません。

ただし、適切に選択されたコメントが最適な場合もあります。

  • それがアルゴリズム自体である場合、その実装(数学のジャーナルに記載され、Mbogoのアルゴリズムと呼ばれるようなもの)だけでなく、複雑で混乱を招く場合は、実装の最初の部分は、「これはウィジェットを再構成するためのMbogoのアルゴリズムです。最初にここで説明されています:[論文のURL]。この実装には、AliceとCarolによる改良が含まれています[別の論文のURL]。」それ以上の詳細には触れないでください。詳細が必要な場合は、おそらく論文全体を読む必要があります。

  • 特殊な表記法で1行または2行として記述できるものを取り、それを命令コードの大きな塊に展開した場合、関数の上にあるコメントにそれらの1行または2行の特殊表記法を配置することは、 想定とは何かを読者に伝えます。これは「コメントがコードと同期しなくなった場合はどうなるか」という例外です。特殊化された表記法はおそらくコードよりもバグを見つけるのがmuch簡単だからです。 (代わりに英語で仕様を書いた場合は、逆になります。)良い例がここにあります https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.cpp# 1057 ...

    /**
     * Scan a unicode-range token.  These match the regular expression
     *
     *     u\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?
     *
     * However, some such tokens are "invalid".  There are three valid forms:
     *
     *     u+[0-9a-f]{x}              1 <= x <= 6
     *     u+[0-9a-f]{x}\?{y}         1 <= x+y <= 6
     *     u+[0-9a-f]{x}-[0-9a-f]{y}  1 <= x <= 6, 1 <= y <= 6
    
  • コードは全体的に単純ですが、lookが非常に複雑、不必要、またはまったく間違っているが、理由によりそのようにする必要がある場合は、コメントを理由を述べる。以下に簡単な例を示します。説明が必要なのは、定数に特定の値がある理由だけです。

    /* s1*s2 <= SIZE_MAX if s1 < K and s2 < K, where K = sqrt(SIZE_MAX+1) */
    const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);
    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
        nmemb > 0 && SIZE_MAX / nmemb < size)
      abort();
    
110
zwol

では、複雑なコードをコメントで説明することの何が問題になっていますか?

それは正誤問題ではなく、「ベストプラクティス」の問題です Wikipediaの記事で定義されています

ベストプラクティスは、他の方法で達成された結果よりも常に優れた結果を示し、ベンチマークとして使用される方法または手法です。

したがって、ベストプラクティスは、最初にコードを改善し、それが不可能な場合は英語を使用することです。

法律ではありませんが、コメントが必要なリファクタリングされたコードよりも、リファクタリングが必要なコメント付きのコードを見つける方がはるかに一般的であり、ベストプラクティスはこれを反映しています。

61
FMJaguar

美しく、完璧に細工された、構造化された、読みやすいコードが機能しない日がやってきます。または、十分に機能しません。または、それが機能せず、調整が必要な特殊なケースが発生します。

その時点で、正しく動作するように変更を加える必要があります。 特にパフォーマンスの問題がある場合だけでなく、使用しているライブラリ、API、Webサービス、gem、またはオペレーティングシステムの1つが期待どおりに動作しないシナリオでも、必ずしもエレガントではないが、直感に反する、または自明ではない提案を行うことになります。

そのアプローチを選択した理由を説明するコメントがない場合、将来誰か(そして誰かがあなたかもしれません)がコードを見る可能性が非常に高いので、コードを「修正」する方法を見てください修正のようには見えませんのため、より読みやすくエレガントな修正を誤って元に戻します。==

誰もが常に完璧なコードを書いていれば、不完全に見えるコードが現実世界からのトリッキーな介入を回避しているのは明らかですが、それは物事が機能する方法ではありません。ほとんどのプログラマーは、しばしば混乱したり、ややもつれたコードを書くので、これに遭遇したとき、それを片付けるのは自然な傾向です。私は自分の過去の自己が実際の馬鹿であることを誓います。

だから私はコメントを悪いコードの謝罪とは考えていませんが、おそらくあなたが明白なことをしなかった理由の説明としてかもしれません。 // The standard approach doesn't work against the 64 bit version of the Frobosticate Libraryは、将来の開発者(将来の自分を含む)がコードのその部分に注意を払い、そのライブラリに対してテストできるようにします。確かに、ソース管理のコミットにもコメントを入れることはできますが、人々は何かがうまくいかなかった場合にのみコメントを見ます。彼らはコードを変更すると、コードのコメントを読みます。

理論的に完璧なコードを常に書くべきだと私たちに言っている人は、実際の環境でプログラミングの経験が豊富な人とは限りません。特定のレベルで機能するコードを作成する必要がある場合もあれば、不完全なシステムと相互運用する必要がある場合もあります。エレガントでよく書かれた方法でこれを行うことができないという意味ではありませんが、自明でない解決策は説明が必要です。

誰も読まないことがわかっている趣味のプロジェクトのコードを書いているとき、私はまだ混乱している部分にコメントします。たとえば、3Dジオメトリには、私が完全に慣れていない数学が含まれます-戻ってきたときに知っているので6か月後には、この方法を完全に忘れてしまいます。これは不正なコードに対する謝罪ではなく、個人的な制限の承認です。コメントを付けずに残しておくことは、将来自分のためにもっと仕事をすることです。私が今それを避けることができるならば、私の将来の自己が不必要に何かを再学習しなければならないことを望まない。それはどのような価値があるでしょうか?

56
glenatron

コメントの必要性は、コードの抽象化レベルに反比例します。

たとえば、アセンブリ言語は、ほとんどの実用的な目的では、コメントなしでは理解できません。以下は、フィボナッチ系列の項を計算して出力する小さなプログラム からの抜粋です

main:   
; initializes the two numbers and the counter.  Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
    mov ax,'00'                     ; initialize to all ASCII zeroes
    mov di,counter                  ; including the counter
    mov cx,digits+cntDigits/2       ; two bytes at a time
    cld                             ; initialize from low to high memory
    rep stosw                       ; write the data
    inc ax                          ; make sure ASCII zero is in al
    mov [num1 + digits - 1],al      ; last digit is one
    mov [num2 + digits - 1],al      ; 
    mov [counter + cntDigits - 1],al

    jmp .bottom         ; done with initialization, so begin

.top
    ; add num1 to num2
    mov di,num1+digits-1
    mov si,num2+digits-1
    mov cx,digits       ; 
    call    AddNumbers  ; num2 += num1
    mov bp,num2         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jz  .done           ;

    ; add num2 to num1
    mov di,num2+digits-1
    mov si,num1+digits-1
    mov cx,digits       ;
    call    AddNumbers  ; num1 += num2
.bottom
    mov bp,num1         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jnz .top            ;
.done
    call    CRLF        ; finish off with CRLF
    mov ax,4c00h        ; terminate
    int 21h             ;

コメントを付けても、理解するのはかなり複雑です。

現代の例:正規表現は、多くの場合、非常に低い抽象構成です(小文字、0、1、2、改行など)。彼らはおそらくサンプルの形でコメントを必要としています(ボブ・マーティン、IIRCはこれを認めています)。 HTTP(S)とFTPのURLに一致するはずの(と思います)正規表現を次に示します。

^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|m
+il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.
+\,\;\?\'\\\+&amp;%\$#\=~_\-]+))*$

言語が抽象化階層を上っていくにつれて、プログラマーは刺激的な抽象化(変数名、関数名、クラス名、モジュール名、インターフェース、コールバックなど)を使用して組み込みのドキュメントを提供できます。これを利用することを怠り、それを紙に書くためにコメントを使用するのは面倒であり、メンテナに不快で無礼です。

Numerical Recipes in Cはほとんど逐語的にNumerical Recipes in C++、私はNumerical Recipes(FORTAN)として、すべての変数aaaで始まると推測します、bcccなどが各バージョンで維持されます。アルゴリズムは正しいかもしれませんが、言語が提供する抽象化を利用していませんでした。そして、彼らは私を元気づけます。ドブス博士の記事 のサンプル-高速フーリエ変換

void four1(double* data, unsigned long nn)
{
    unsigned long n, mmax, m, j, istep, i;
    double wtemp, wr, wpr, wpi, wi, theta;
    double tempr, tempi;

    // reverse-binary reindexing
    n = nn<<1;
    j=1;
    for (i=1; i<n; i+=2) {
        if (j>i) {
            swap(data[j-1], data[i-1]);
            swap(data[j], data[i]);
        }
        m = nn;
        while (m>=2 && j>m) {
            j -= m;
            m >>= 1;
        }
        j += m;
    };

    // here begins the Danielson-Lanczos section
    mmax=2;
    while (n>mmax) {
        istep = mmax<<1;
        theta = -(2*M_PI/mmax);
        wtemp = sin(0.5*theta);
        wpr = -2.0*wtemp*wtemp;
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        for (m=1; m < mmax; m += 2) {
            for (i=m; i <= n; i += istep) {
                j=i+mmax;
                tempr = wr*data[j-1] - wi*data[j];
                tempi = wr * data[j] + wi*data[j-1];

                data[j-1] = data[i-1] - tempr;
                data[j] = data[i] - tempi;
                data[i-1] += tempr;
                data[i] += tempi;
            }
            wtemp=wr;
            wr += wr*wpr - wi*wpi;
            wi += wi*wpr + wtemp*wpi;
        }
        mmax=istep;
    }
}

抽象化に関する特別なケースとして、すべての言語には、特定の一般的なタスク(Cで動的リンクリストを削除する)のイディオム/正規コードスニペットがあり、それらがどのように見えるかに関係なく、それらは文書化されるべきではありません。これらのイディオムは非公式に言語の一部であるため、プログラマーはこれらのイディオムを学ぶ必要があります。

したがって、要注意:回避できない低レベルのビルディングブロックから構築された非慣用的なコードにはコメントが必要です。そして、これはそれが起こるより少ない必要なWAAAAYです。

29
Kristian H

コードのコメントに問題があるとは思いません。コメントがどういうわけかbad私の意見では、一部のプログラマは物事をやりすぎているためです。この業界には、特に極端な見方に向けて多くのバンドワゴンがあります。途中でコメント付きのコードが不良コードと同等になりましたが、その理由はわかりません。

コメントには問題があります-コメントが参照するコードを更新するときは、コメントを更新し続ける必要があります。 wikiか何かは、コードについての完全なドキュメンテーションのためのより適切なリソースです。コードは、コメントを必要とせずに読みやすくする必要があります。バージョン管理またはリビジョンノートは、行ったコードの変更を記述する場所にする必要があります。

ただし、上記のいずれもコメントの使用を無効にしません。私たちは理想的な世界に住んでいるわけではないので、上記のいずれかが何らかの理由で失敗した場合、フォールバックするsomeコメントが必要です。

21
Roy

彼の言っていることを少し読みすぎていると思います。苦情には2つの異なる部分があります。

(1)複雑なアルゴリズム、または(2)説明コメント付きの長く複雑なコードを説明することの何が問題になっていますか?

(1)は避けられない。マーティンがあなたに反対することはないと思います。 高速な逆平方根 のようなものを書いている場合、たとえそれが単に「邪悪な浮動小数点ビットレベルのハッキング」であっても、コメントが必要になります。 DFSやバイナリ検索のような単純なものを除けば、コードを読んでいる人がそのアルゴリズムの経験を持っているとは考えにくいので、それが何であるかについてのコメントで少なくとも言及があるはずです。

ただし、ほとんどのコードは(1)ではありません。手作業でのミューテックス実装、ライブラリサポートが不十分なあいまいな線形代数演算、自社の研究グループだけが知っている新しいアルゴリズムにすぎないソフトウェアを書くことはめったにありません。ほとんどのコードは、ライブラリ/フレームワーク/ API呼び出し、IO、ボイラープレート、ユニットテストで構成されています。

これは、マーティンが話している種類のコードです。そして彼は、章の上部にあるカーニハンと笑い声からの引用であなたの質問に対処します:

不正なコードはコメントしないでください。書き直してください。

コードに長い複雑なセクションがある場合、コードをクリーンに保つことができません。この問題の最善の解決策は、ファイルの先頭に段落が長いコメントを書いて、将来の開発者がそれを混乱させるのを助けることではありません。最善の解決策は、それを書き直すことです。

そして、これはまさにマーティンが言うことです:

コメントの適切な使用は、コードで自分自身を表現することに失敗したことを補うことです...コメントは常に失敗です。それらなしで自分を表現する方法を理解しますが、それらの使用はお祝いの原因ではありません。

これはあなたの(2)です。マーティンは、長く複雑なコードにはコメントが必要であることにも同意します。彼はそれを主張します:

コメントの少ない明確で表現力豊かなコードは、コメントの多い雑然とした複雑なコードよりもはるかに優れています。あなたが作った混乱を説明するコメントを書くことに時間を費やすのではなく、その混乱を掃除することに費やしてください。

18
Patrick Collins

複雑なアルゴリズムや、長く複雑なコードを説明的なコメントで説明することの何が問題になっていますか?

そのようなものは何もありません。作業を文書化することは良い習慣です。

とは言っても、ここでは誤った二分法があります。クリーンなコードを作成することとドキュメント化されたコードを作成することの2つは対立していません。

注目すべきは、「複雑なコードがコメント化されている限り問題ない」と考える代わりに、複雑なコードを単純化してより単純なコードに抽象化することです。

理想的には、コードはシンプルである必要がありますand文書化されています。

このようにして、他の開発者(自分を含む)がアルゴリズム全体を1行ずつ読み取ってその内容を理解する代わりに、平易な英語で書いたわかりやすい説明コメントを読むだけで済みます。

そうだね。これが、すべてのパブリックAPIアルゴリズムをドキュメントで説明する必要がある理由です。

それでは、部分的に人間が読めるプログラミング言語で書かれた複雑なコードを書いた後、コードの操作をわかりやすくわかりやすい英語で説明する簡潔なコメントを追加してみませんか?

理想的には、複雑なコードを書いた後、次のことを行う必要があります(完全なリストではありません)。

  • ドラフトと見なしてください(つまり、それを書き直す予定です)
  • アルゴリズムのエントリポイント/インターフェイス/ロール/などを形式化します(インターフェイスの分析と最適化、抽象化の形式化、前提条件、事後条件と副作用の文書化、およびエラーケースの文書化)。
  • テストを書く
  • クリーンアップとリファクタリング

これらの手順はどれも簡単なものではなく(つまり、それぞれに数時間かかる場合があります)、それらを実行することによる報酬はすぐには得られません。そのため、これらの手順は(ほぼ)常に妥協されています(開発者が手抜きをする、マネージャーが手抜きをする、期限、市場の制約/その他の現実の状況、経験の欠如など)。

[...]一部のアルゴリズムは複雑です。したがって、それらを1行ずつ読むと理解が困難になります。

APIの機能を理解するために実装を読む必要はありません。これを行うと、(インターフェースではなく)実装に基づいてクライアントコードを実装します。つまり、モジュールの結合がalreadyとんでもないことを意味し、ドキュメント化されていない依存関係がすべての新しい行に導入される可能性があります。あなたが書いて、すでに技術的負債を追加しているコード。

一般的な操作についての数行のコメントで複雑なアルゴリズムを説明するのは本当に悪いことですか?

いいえ-それは良いです。コメントを数行追加するだけでは十分ではありません。

コメントで複雑なコードを説明することの何が問題になっていますか?

回避できるのであれば、複雑なコードを使用するべきではないという事実。

複雑なコードを回避するには、インターフェースを形式化し、実装に費やすよりもAPI設計に8倍以上費やし(Stepanovは、実装に比べてインターフェースに少なくとも10倍費やすことを提案しました)、次の知識を持つプロジェクトの開発に進みます。アルゴリズムを作成するだけでなく、プロジェクトを作成しています。

プロジェクトには、APIドキュメント、機能ドキュメント、コード/品質測定、プロジェクト管理などが含まれます。これらのプロセスはいずれも、1回限りの迅速な手順ではありません(すべて時間がかかり、事前の検討と計画が必要です。また、すべて定期的にプロセスに戻って詳細を修正/完了する必要があります)。

8
utnapistim

他の開発者(自分自身を含む)がアルゴリズム全体を1行ずつ読んでアルゴリズムを理解する代わりに、平易な英語で書いたわかりやすい説明コメントを読むだけで済みます。

私はこれを「コメント」のわずかな乱用と考えます。プログラマーが何かを読みたい場合の代わりにアルゴリズム全体、そしてそれが関数ドキュメントの目的です。わかりました。関数のドキュメントは実際にはソース内のコメントに表示される可能性があります(おそらくdocツールによる抽出用)。しかし、構文的にはコンパイラに関する限りコメントですが、別々の目的で個別に検討する必要があります。 「コメントは少なくなければならない」とは必ずしも「ドキュメントが少なくなければならない」または「著作権表示が不足している」という意味であるとは思いません。

関数内のコメントは、誰かが同様にコードを読むためのものです。したがって、コードに理解しにくい数行があり、それらを簡単に理解できない場合、コメントは読者がそれらの行のプレースホルダーとして使用するのに役立ちます。これは、読者が一般的な要旨を取得しようとしているだけのときに非常に役立ちますが、いくつかの問題があります。

  • コメントは必ずしも真実であるとは限りませんが、コードはそれが行うことを行います。ですから、読者はあなたの言葉をそれに取っており、これは理想的ではありません。
  • 読者はまだコード自体を理解していないため、後でコードに戻るまで、コードを変更または再利用する資格がありません。その場合、彼らはそれを読んで何をしていますか?

例外はありますが、ほとんどの読者はコード自体を理解する必要があります。コメントは、それを置き換えるためではなく、それを支援するために書く必要があります。そのため、コメントには「なぜそれをしているのか」と記載するように勧められています。コードの次の数行の動機を知っている読者は、彼らが何をどのように行うかを知るチャンスがより高くなります。

6
Steve Jessop

どこで読んだか忘れてしまいましたが、コードに表示される内容とコメントとして表示される内容の間に明確な線があります(== --- ==)

私はあなたがアルゴリズムではなく意図をコメントするべきだと信じています。つまりあなたが何をすべきかではなく、あなたが何をすべきかをコメントしてください

例えば:

// The getter.
public <V> V get(final K key, Class<V> type) {
  // Has it run yet?
  Future<Object> f = multitons.get(key);
  if (f == null) {
    // No! Make the task that runs it.
    FutureTask<Object> ft = new FutureTask<Object>(
            new Callable() {

              public Object call() throws Exception {
                // Only do the create when called to do so.
                return key.create();
              }

            });
    // Only put if not there.
    f = multitons.putIfAbsent(key, ft);
    if (f == null) {
      // We replaced null so we successfully put. We were first!
      f = ft;
      // Initiate the task.
      ft.run();
    }
  }
  try {
    /**
     * If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
     * then you are trying to get from your Multiton in your creator.
     *
     * Cannot check for that without unnecessarily complex code.
     *
     * Perhaps could use get with timeout.
     */
    // Cast here to force the right type.
    return (V) f.get();
  } catch (Exception ex) {
    // Hide exceptions without discarding them.
    throw Throwables.asRuntimeException(ex);
  }
}

ここでは、各ステップが何を実行するかを説明する試みはありません。すべてのステップが想定されるものであると説明しているだけです。

PS:私が参照していたソースを見つけました- コーディングホラー:コードが教えてくれ、コメントが理由を教えてくれます

5
OldCurmudgeon

多くの場合、複雑なことをしなければなりません。将来の理解のためにそれらを文書化することは確かに正しいです。このドキュメントの適切な場所がコード内にある場合があります。この場合、ドキュメントはコードで最新の状態に保つことができます。ただし、個別のドキュメントを検討する価値は間違いありません。これは、図やカラー写真など、他の人に簡単に提示できる場合もあります。次に、コメントは次のとおりです。

// This code implements the algorithm described in requirements document 239.

または単に

void doPRD239Algorithm() { ...

確かに人々はMatchStringKnuthMorrisPrattまたはencryptAESまたはpartitionBSPという名前の関数に満足しています。もっとあいまいな名前はコメントで説明する価値があります。書誌データと、アルゴリズムを実装した論文へのリンクを追加することもできます。

アルゴリズムが複雑で斬新で、明白でない場合は、たとえ社内の循環のためだけであっても、それは間違いなくドキュメントの価値があります。ドキュメントが失われることが心配な場合は、ドキュメントをソース管理にチェックインしてください。

官僚的ほどアルゴリズム的ではないコードの別のカテゴリがあります。別のシステムのパラメーターを設定するか、他の誰かのバグと相互運用する必要があります。

/* Configure the beam controller and turn on the laser.
The sequence is timing-critical and this code must run with interrupts disabled.
Note that the constant 0xef45ab87 differs from the vendor documentation; the vendor
is wrong in this case.
Some of these operations write the same value multiple times. Do not attempt
to optimise this code by removing seemingly redundant operations.
*/
5
pjc50

しかし、それで十分ではないことは誰でも知っています。

本当に?いつから?

優れた名前を持つ適切に設計されたコードは、ほとんどの場合十分です。コメントの使用に対する反対論はよく知られ、文書化されています(参照しているとおり)。

しかし、これらは(他のように)ガイドラインです。まれなケース(私の経験では、約2年に1回)で、より小さな読みやすい関数にリファクタリングすると(パフォーマンスまたは凝集の必要性により)事態が悪化する場合があります-次に、実際に何が起こっているかを説明する長いコメントを入力してくださいしている(そして、なぜあなたがベストプラクティスに違反しているのか)。

4
Telastyn

コードの主な目的は、コンピュータに何かをするように命令することです。したがって、コメントを実行できないため、適切なコメントが適切なコードの代わりになることはありません。

そうは言っても、ソース内のコメントは、他のプログラマー(自分を含む)向けのドキュメントの1つの形式です。コメントが、コードが各ステップで行っていることよりも抽象的な問題に関するものである場合、平均よりも優れています。その抽象化のレベルは、使用しているツールによって異なります。アセンブリ言語ルーチンに付随するコメントは、通常、たとえばこのAPLよりも「抽象化」のレベルが低くなります A←0⋄A⊣{2⊤⍵:1+3×⍵⋄⍵÷2}⍣{⍺=A+←1}⎕ 。おそらく、それが解決しようとしている問題についてコメントする価値があると思います。

2
Scott Leadley

コードが些細なものであれば、説明コメントは必要ありません。コードが自明でない場合、説明コメントも自明ではないでしょう。

さて、自明ではない自然言語の問題は、私たちの多くはそれを読んだり書いたりすることがあまり得意ではないということです。筆記のコミュニケーション能力は優れていると思いますが、それでも筆記言語をあまり理解していない人はあなたの言葉を誤解するかもしれません。

誤って解釈できない自然言語を非常に作成しようとすると、最終的には法的文書のようなものになります(そして、私たち全員が知っているように、これらはコードよりも詳細で理解が困難です)。

コードはロジックの最も簡潔な説明である必要があり、コンパイラとプラットフォームが最終決定権を持っているため、コードの意味についてはあまり議論すべきではありません。

個人的にはコメントを書いてはいけないと言っているわけではありません。コードにコメントが必要な理由と、それを修正する方法を検討する必要があるのはそれだけです。これは、ここでの回答では共通のテーマのようです。

2
Martin

まだ言及されていない1つのポイントは、言語が特定の構文を複数の目的で使用する場合に、コードの一部について正確にコメントすることが役立つ場合があることです。たとえば、すべての変数のタイプがfloatであるとすると、次のことを考慮してください。

f1 = (float)(f2+f3); // Force result to be rounded to single precision
f4 = f1-f2;

floatfloatに明示的にキャストすると、結果が強制的に単精度に丸められます。したがって、コメントは単にコードが何をするかを言っていると見なすことができます。一方、そのコードを次のコードと比較してください。

thing.someFloatProperty = (float)(f2*0.1); // Divide by ten

ここで、キャストの目的は、コンパイラーが正確に計算する最も効率的な方法(f2/10)でスコーキングしないようにすることです[0.1fを掛けるよりも正確であり、ほとんどのマシンでは10.0fで割るよりも高速です]。

コメントがないと、以前のコードをレビューしていた人は、コンパイラーが誤動作しないようにする必要があり、その必要がないという誤った考えでキャストが追加されたと考えるかもしれません。実際、キャストは、言語仕様に記載されているとおりの処理を実行する目的を果たします。計算をより高い精度で保持するよりも丸めの方がコストがかかるマシンでも、計算の結果を単精度に丸めます。 floatへのキャストはさまざまな意味と目的を持つことができるため、特定のシナリオで意図されている意味をコメントで指定すると、実際の意味が意図と一致していることが明確になります。

0
supercat