「コメントは『何』について説明すべきだ(2017)」

2026/01/04 19:43

「コメントは『何』について説明すべきだ(2017)」

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

概要:
記事は、コメントが「何を」コードが行っているかと「なぜ」書かれたのかを説明すべきだと主張していますが、それらが価値を付加する場合にのみです。短い変数名(例:

w
r
p
)は意図を曖昧にし、読者がコメントに頼るよう促します。説明的なコメント―例えば
// Clear twice to deal with bug ABC in library XYZ
―が移動または再フォーマットされると、その根拠が失われ、git blame のようなツールで復元するのが困難になります。「なぜ」情報をコミットメッセージやテストに頼ると、コンテキストスイッチが発生し、コメントがすぐに表示されない場合に危険な仮定につながる可能性があります。説明的なコメントを参照するコードの隣に保つことで検索時間が短縮され、誤解釈リスクが低減します。この議論では、リファクタリング後にコメント付き行が消失したバグと、多数の小さなメソッドであっても関数間をジャンプし続ける必要があるボブ・マーティンの例が引用され、可読性とコンテキストスイッチのバランスが強調されています。最後に著者は、コメントはツールであり、クリーンコードの代替ではないことを読者に思い出させ、「何」と「なぜ」のコメントの適切な組み合わせについて継続的な“炎上”議論を呼びかけています。

この改訂版は10項目すべてを取り入れ、クリーンコードとの関係におけるコメントの役割を明確化し、元のメッセージの明瞭さと焦点を保っています。

本文

人は「コメントは『何』ではなく『なぜ』を説明すべきだ」とよく言います。
私は今、コメントに「何」を説明させるべきだと主張したいので、炎上戦争の種になるかもしれませんが、その点について議論してみます。ただし、これを悪コードを書くための口実に使わないでくださいね。


なぜ「何」を説明するコメントは必要ない?

コメントで「何が起きているか」を説明する必要があるとすれば、ということはあなたのコード自体が不明瞭だということを示しています。
例として:

// weight, radius, price
w = 10; r = 9; p = 1;

より

weight = 10; radius = 9; price = 3;

のほうが明確です。

w
が「重量」であることは、連続して書かれた行を見れば直感的に分かりますが、その後で
w
の意味を確認するためにコードの別箇所へ移動しなければならず、文脈切替が発生します。
その結果、誤って「幅(width)」と勘違いしたり、重大なバグにつながる危険性があります。コメントはきれいなコードの代わりにはなりません。


なぜ「なぜ」を説明するコメントは必要か?

一部では「なぜ」についてはコミットメッセージやテストに書くべきだと主張しますが、実際には多くの人がそれを不自然だと感じます。

// Clear twice to deal with bug ABC in library XYZ, see [link]
XYZ.clear(); 
XYZ.clear();

このコメントを削除してコミットメッセージに移すことは可能でしょうか?
もし「なぜ

XYZ.clear()
を2回呼ぶのか」を知りたければ、コミットログまで遡らなくてはいけません。行がリファクタリングされたり別ファイルへ移動した場合には
git blame
も機能しないことがあります。
その検索は文脈切替であり、時に「不要なバグだ」と誤って判断してしまう危険性があります。

これら2つのケースは同じ問題を共有しています:情報を探す作業が難しいという点です。

  • 最悪の場合:時間のかかる文脈切替
  • もっとひどい場合:不正確な仮定

したがって、必要な情報は「コード自体」もしくは「コメント」の中に残す方が安全です。


「変わった」ケース

説明的なコードが逆に文脈切替を強いることがあります。Bob Martin の Extract‑Till‑You‑Drop から例を取り上げます。

String replace() {
    Pattern symbolPattern = Pattern.compile("\\$([a-zA-Z]\\w*)");
    Matcher symbolMatcher = symbolPattern.matcher(stringToReplace);
    while (symbolMatcher.find()) {
        String symbolName = symbolMatcher.group(1);
        if (getSymbol(symbolName) != null && !alreadyReplaced.contains(symbolName)) {
            alreadyReplaced.add(symbolName);
            stringToReplace = stringToReplace.replace("$" + symbolName,
                                                     translate(symbolName));
        }
    }
    return stringToReplace;
}

Martin はこれを次のようにリファクタリングします。

String replace() {
    replaceAllSymbols();
    return stringToReplace;
}

private void replaceAllSymbols() {
    for (String symbolName = nextSymbol(); symbolName != null; 
         symbolName = nextSymbol())
        replaceAllInstances(symbolName);
}

さらに下位メソッドへ分割していきます。
結果として

replace()
はわずか2行ですが、クラス全体を理解するには6つの別メソッドに飛び回る必要があります。「読みやすくなった?」という質問に対し、バグ追跡中で上下へスクロールしながらメソッド間をジャンプするのは実際には手間が増えます。

このような場合、コメントによって「何」を説明しておけば別メソッドへ飛び回る必要がなくなるので理解しやすくなります。もちろん全ての場合に当てはまるわけではありませんが、「何」についてコメントを書くのが適切なケースも存在します。これらを一括りに否定するべきではありません。

String replace() {
    Pattern symbolPattern = Pattern.compile("\\$([a-zA-Z]\\w*)"); // 例:$F1a3
    Matcher symbolMatcher = symbolPattern.matcher(stringToReplace);

    // 全シンボルを置換
    while (symbolMatcher.find()) {
        String symbolName = symbolMatcher.group(1);
        // translate はすべてのインスタンスを置換するので、一度だけ実行すればよい
        if (getSymbol(symbolName) != null && !alreadyReplaced.contains(symbolName)) {
            alreadyReplaced.add(symbolName);
            stringToReplace = stringToReplace.replace("$" + symbolName,
                                                     translate(symbolName));
        }
    }
    return stringToReplace;
}

このバージョンは、オリジナルやリファクタリング版よりも「何」を理解しやすいです。もちろんコメントが不要なケースも多々ありますが、「何」について説明することが正しい選択になる場面は確かに存在します。


まとめ

  • コード自体が不明瞭であれば、「何」を説明するコメントが必要になります。
  • 「なぜ」の理由はできるだけコードやコミットメッセージに残し、コメントはそれを補完する形で使用します。
  • コメントとリファクタリングのバランスを取りながら、情報へのアクセスコストを最小限に抑えることが重要です。

以上が私の主張です。炎上戦争になりそうですが、ご賛否自由です!

同じ日のほかのニュース

一覧に戻る →

2026/01/05 6:01

北ダコタ州法は、石炭業界の弁護士の名前に由来する偽の「クリティカルミネラル」を一覧化しています。

## Japanese Translation: **改善された要約** 記事には「State(州)」「Zip Code(郵便番号)」「Country(国)」の3つのセクション見出しのみが含まれています。これらの見出しの下に追加のテキスト、説明、または例はありません。

2026/01/05 5:17

**Show HN: AWS用ターミナル UI**

## Japanese Translation: > **概要:** > tawsはRustで書かれた軽量なターミナルUIで、k9sに触発されており、ユーザーがAWSリソースを迅速かつ効率的に管理できるようにします。リアルタイム更新、Vim風ナビゲーション(`k/j/↑/↓`, `g/G`)、リソース操作(例:EC2の開始/停止/終了は`s/S/T`)、JSON/YAMLビュー、フィルタリング、ファジー補完、およびコロン(`:`)で呼び出すリソースピッカーをサポートします。 > このツールは30個の主要AWSサービス(典型的な使用率の95%以上)にわたって動作し、マルチプロファイル/マルチリージョンナビゲーション(`p`, `R`)が可能です。Homebrew(`brew install huseyinbabal/tap/taws`)でインストールできるほか、macOS、Linux、Windows向けに事前構築済みバイナリをダウンロードして使用できます。macOS/Linux用のクイックインストールスクリプトも提供されています。 > AWS認証情報は`aws configure`、環境変数、またはIAMロールで供給でき、必要最低限の権限はDescribe*とList*です。本プロジェクトはMITライセンスで配布されており、新しいサービスを追加する前にディスカッションが奨励されています。将来のリリースではサービス対応範囲の拡大を目指し、IAM権限ギャップ、ページネーション制限、グローバルサービスデフォルトなど既知の問題にも対処します。 この改訂された概要は主要なポイントすべてを網羅しており、元の内容に忠実で、読者にとって明確かつ簡潔な概要を提供します。

2026/01/05 4:48

**Claude Code On‑the‑Go** (クレオード・コード・オンザゴー)

## Japanese Translation: **(修正版)** > 著者は、iPhone 上で 6 つの Claude Code エージェントを実行する、コスト管理済みかつモバイルフレンドリーなワークフローを構築します。 > > * **Vultr VM**(Silicon Valley の `vhf‑8c‑32gb`)を 2 本のスクリプト(`vm-start`、`vm-stop`)で起動・停止し、iOS ショートカットから呼び出します。VM は稼働時に約 **$0.29 / hr(約 $7/日)** の費用がかかります。 > > * 接続は **Tailscale のプライベートネットワーク** を介し、**Termius + mosh** で行い、Wi‑Fi / モバイル通信の切り替えや電話機のスリープ時でも継続する頑健な SSH セッションを実現します(SSH エージェントは転送されないため、GitHub 認証は tmux 内の通常キーで行います)。 > > * ログイン時にシェルが自動的に **tmux** にアタッチします(`if [[ -z "$TMUX" ]]; then tmux attach -t main || tmux new -s main fi`)、再接続時も状態を保持します。 > > * 各 Claude エージェントは、別々の Git 作業ツリー・ブランチに紐付けられた独自の tmux ウィンドウで実行されます。ポート番号は `django_port = 8001 + (hash_val % 99)` により決定的に割り当てられ、`hash_val = sum(ord(c) for c in branch_name)` です。 > > * `~/.claude/settings.json` の **PreToolUse フック** はタスク完了時に Poke にプッシュ通知を送信します。質問は `jq` で抽出し、メッセージを構築して `curl` で送信します。 > > * 全体のセットアップは、セキュリティ上隔離された消耗性 VM を使用し、潜在的な無制限利用を日次コストキャップ(約 $7)に限定しています。 > > * 開発者は電話で 10–20 分程度の Claude タスクを開始し、その間他の作業を行いながら通知が来るまで待つことができます。 この修正版要約は、すべての主要ポイントを完全に反映し、推論を避け、曖昧な表現を排除して情報を明確に提示しています。