コメントアウトされたコードは貴重なドキュメントになりますか?


83

次のコードを書きました。

if (boutique == null) {
    boutique = new Boutique();

    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.persist(boutique);
} else {
    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    //boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.merge(boutique);
}

ここにはコメントアウトされた行があります。しかし、私はそれが差が間にあるものを明らかにすることにより、コードが明確になり考えるifelse。違いは、色の強調表示でさらに顕著です。

このようなコードをコメントアウトするのは良い考えでしょうか?

回答:


109

答えのほとんどは、この特定のケースをリファクタリングする方法に焦点を当てていますが、コメントアウトされたコードが通常悪いのはなぜかという一般的な答えを提供します。

まず、コメントアウトされたコードはコンパイルされません。これは明らかですが、次のことを意味します。

  1. コードが機能しないこともあります。

  2. コメントの依存関係が変更されても、明らかに壊れることはありません。

コメントされたコードは非常に「デッドコード」です。長く座っているほど腐り、次の開発者に提供する価値はますます少なくなります。

第二に、目的は不明です。ランダムにコメント化された行がある理由のコンテキストを提供する長いコメントが本当に必要です。コメントされたコード行だけを見たとき、なぜそこにたどり着いたのかを理解するために、どうやってそこにたどり着いたのかを調べなければなりません。誰が書いたの?何をコミットしますか?コミットメッセージ/コンテキストは何でしたか?等。

代替案を検討してください:

  • 目標が関数/ APIの使用例を提供することである場合は、単体テストを提供します。単体テストは実際のコードであり、正しくない場合は壊れます。
  • コードの以前のバージョンを保持することが目的の場合は、ソース管理を使用します。以前のバージョンをチェックアウトし、コードベース全体でコメントを切り替えて変更を「元に戻す」ことをお勧めします。
  • 目的が同じコードの代替バージョンを維持することである場合は、ソース管理を再度使用します。結局のところ、これがブランチの目的です。
  • 目的が構造を明確にすることである場合は、コードを再構築してより明確にする方法を検討してください。他の回答のほとんどは、これを行う方法の良い例です。

5
あなたは1つの重要な理由を見逃していると思います:ドキュメント:目的が代替設計オプションをドキュメント化することである場合、代替の説明、特に破棄された理由を元のコードの代わりに提供する必要があります。
サリアン

14
設計オプションは、プログラミング言語よりも人間の言語で説明する方が適切です。
マークE.ハセ14

3
プロジェクトを引き継いだ後続の開発者は、ソース管理に代替/前/失敗した実装が存在することをどのようにして知ることができますか?新しい開発者は、すべてのバージョン履歴と変更ログを確認する予定ですか?または、コメントを使用して、すべての有用な代替実装の前のコミットのハッシュにリンクすることは一般的な習慣ですか?もしそうなら、私は気づきませんでした。
Moobie

ただし、これには注意点が1つあります。場合によっては、2つの同等のコードアプローチでは、一方のパフォーマンスが向上し、他方が読み取り可能になるという点で、パフォーマンスと安定性が異なる場合があります。このような場合、パフォーマンスバリアントを使用してもかまいませんが、コードの目的を理解しやすくするために、読み取り可能なバリアントをコメントに入れてください。場合によっては、(コメント化された)コード行が冗長な説明よりも明確になることがあります。
フラット

263

このコードの最大の問題は、これらの6行を複製したことです。その重複を排除すると、そのコメントは役に立ちません。

boutiqueDao.mergeOrPersistメソッドを作成する場合、これを次のように書き換えることができます。

if (boutique == null) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

boutiqueDao.mergeOrPersist(boutique);

特定のオブジェクトを作成または更新するコードは一般的であるため、たとえばmergeOrPersistメソッドを作成するなどして、一度解決する必要があります。確かに、これら2つのケースのすべての割り当てコードを複製しないでください。

多くのORMは、何らかの方法でこれをサポートしています。たとえば、idがゼロの場合は新しい行を作成し、がゼロでidない場合は既存の行を更新します。正確な形式は、問題のORMに依存します。また、使用しているテクノロジーに詳しくないので、それを支援することはできません。


mergeOrPersistメソッドを作成したくない場合は、isNewBoutiqueフラグを導入するなど、他の方法で重複を排除する必要があります。それはきれいではないかもしれませんが、割り当てロジック全体を複製するよりもはるかに優れています。

bool isNewBoutique = boutique == null;
if (isNewBoutique) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

if (isNewBoutique)
    boutiqueDao.persist(boutique);
else
    boutiqueDao.merge(boutique);

166

これは絶対に恐ろしい考えです。意図が明確ではありません。開発者は誤って行をコメントアウトしましたか?何かをテストするには?どうしたの?!

どちらの場合もまったく等しい6行が表示されるという事実は別として。むしろ、このコードの重複を防ぐ必要があります。その後、ある場合にはsetSelectedを追加で呼び出すことがより明確になります。


9
同意した。コメントアウトされた行は、削除された古い動作であると思われます。コメントが必要な場合は、コードではなく自然言語である必要があります。
ジュール

4
私は完全に同意します!私は最近、このプラクティスのためにほとんど完全に読めない継承したいくつかのアプリケーションを理解し、クリーンアップしようと何時間も費やしました。また、他のすべてのコードから切断されているが削除されていないコードも含まれます!これがバージョン管理システムの主な目的だと思います。コメントと変更点があります。最終的には、この練習のために、少なくとも2週間の作業が私のプレートに追加されました。
-bsara


120

いいえ、それはひどい考えです。そのコードに基づいて、次の考えが思い浮かびます。

  • 開発者がデバッグしていたため、この行を以前の状態に戻すのを忘れていたため、この行はコメント化されています
  • この行は、かつてはビジネスロジックの一部だったためコメントアウトされていますが、もはやそうではありません
  • この行は、本番環境でパフォーマンスの問題を引き起こし、開発者は本番システムにどのような影響があるのか​​を確認したいため、コメント化されています

数千行のコメントアウトされたコードを見た後、私はそれを見たときに唯一の賢明なことをしています:すぐにそれを削除します。

コメントアウトされたコードをリポジトリにチェックインする合理的な理由はありません。

また、コードは多くの重複を使用します。できるだけ早く人間が読みやすいように最適化することをお勧めします。


1
しかし、重複したコードを取り除くと、最適化とはほとんど思えません。
アレクシスDufrenoy

23
それは人間の可読性の最適化です
jk。

11
@Trarothは、速度、メモリ使用量、消費電力、またはその他のメトリックを最適化できるため、読みやすさを最適化できないとは思われません(メトリックとしては少しウールです)
jk。

3
確かに、私は人間の可読性を意味しました。ここでの小さなヒント:プログラミングで最も重要な責任はコードです。ですから、ここにあるのは本当に少ないです。
ディベッケ

4
責任としてのソフトウェアもc2.com/cgi/wiki?SoftwareAsLiabilityで扱われます。そこから:「より多くのコードを生成することは必ずしも利益ではありません。コードはテストと保守に費用がかかります。デッドコードをコメントアウトせずに、削除するだけです。コメントアウトされたコードは古く、役に立たないので非常に高速なので、後で削除するよりも早く削除して、混乱を解消することができます。 」
ninjalj

51

CodesInChaosの答えに追加したいのは、それをさらに小さなメソッドにリファクタリングできることを指摘することです。構成によって共通の機能を共有すると、条件が回避されます。

function fill(boutique) {    
  boutique.setSite(site);
  boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
  boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
  boutique.setNom(fluxBoutique.getNom());
  boutique.setIdWebSC(fluxBoutique.getId());
  boutique.setDateModification(new Date());
}    

function create() {
  boutique = new Boutique();      
  fill(boutique);
  boutique.setSelected(false);
  return boutiqueDao.persist(boutique);
}

function update(boutique) {
  fill(boutiquie);
  return boutiquieDao.merge(boutique); 
}

function createOrUpdate(boutique) {
  if (boutique == null) {
    return create();
  }
  return update(boutique);  
}

6
ここで最もクリーンな提案だと思います。
アレクシスDufrenoy

+1。また、nullオブジェクトの回り込みを避けるほど、より良いことを付け加えます(このソリューションは良い例だと思います)。
ナディールサンパオリ

私は渡すboutiqueDaoへの入力としてcreateupdate
ハッピーグリーンキッドナップス

これはどのように動作しますか?createを呼び出すタイミングとupdateを呼び出すタイミングをどのように知ることができますか?元のコードはブティックを見て、更新または作成する必要があるかどうかを知っています。あなたが...作成または更新呼び出すまで、これは単に何もしない
Lyrion

Lyrion:些細なことですが、わかりやすくするためにそのコードも追加します。
アレクサンダートーストリング

27

これは明らかにコメントアウトされたコードの良いケースではありませんが、私はそれを正当化すると思う状況があります:

// The following code is obvious but does not work because of <x>
// <offending code>
<uglier answer that actually does work>

明らかな改善はそうではないというのは、後でそれを見る人への警告です。

編集:私は小さなことについて話している。大きい場合は、代わりに説明します。


5
何が問題なの// the following part done like it is because of Xですか?何か特別な方法でやらなかった理由ではなくなぜあなたがしたように何かをしたのを説明してください。あなたの特定の例では、コメントアウトされたコードの潜在的に大きなブロックの必要性を完全に排除します。(私はダウン投票しませんでしたが、これがダウン投票される理由を確かに見ることができます。)
CVn

13
マイケル、それは(後で日/週/月をし、自分自身)他のプログラマーにそれが明確になるため、はい、あなたはそれをやったことクリーナー/もっと巧妙なアプローチを試してみてください、ない、それがためにXの動作しませんでしたので、彼らはいけませんもう一度やってみてください。これは完全に正当なアプローチであり、この悲しげに埋められた答えを支持したと思います。
ギャレットオルブライト

1
@GarrettAlbright:ありがとう、誰かがそれを手に入れるのを見てうれしい。
ローレンペクテル

3
@LorenPechtel:それだけでなく、多かれ少なかれまったく同じことを書いていました。どの「明らかな」解決策がすでに成功せずに試行されているのか、そしてなぜ機能しないのかをすぐに知ることが非常に役立つ状況があります。
JensG 14

3
説明に失敗したコードに加えて、別の本番環境でより効率的なコードの代替実装もコメントアウトします。たとえば、アルゴリズムの単純な指数時間バージョンと複雑な多項式時間バージョンの両方をコーディングしました。しかし、現在の生産でnは小さく、指数関数的アルゴリズムははるかに高速です。n後で何らかの形で変更された場合、プロジェクトをフォローアップする将来の開発者は、ソース管理での数百件のコミットの奥深くに埋め込まれたコードの異なる実装をどのように知るでしょうか?
Moobie

14

この特定の例では、主にDibkkeの回答で概説されている理由により、コメントアウトされたコードは非常に曖昧です。他の人は、これを行う誘惑さえ避けるためにコードをリファクタリングする方法を提案していますが、何らかの理由でそれが不可能な場合(たとえば、行が似ていますが、十分に近くない)、私は次のようなコメントを歓迎します:

//このブティックの選択を解除する必要はありません。[何でも]

ただし、コードを残したり(コメントアウトしたり)コードを非難できない状況もあると思います。MATLABやNumPYなどを使用する場合、多くの場合、1)配列を反復処理して一度に1つの要素を処理するか、2)配列全体を一度に操作する同等のコードを記述できます。場合によっては、後者のほうがはるかに高速ですが、読むのがはるかに困難です。一部のコードをベクトル化された同等のコードに置き換える場合、次のように元のコードを近くのコメントに埋め込みます。

%%以下のベクトル化されたコードはこれを行います。

% for ii in 1:N
%    for jj in 1:N
%      etc.

%ただし、マトリックスバージョンは標準入力で最大15倍高速に実行されます(MK、2013年3月10日)

明らかに、2つのバージョンが実際に同じことを行い、コメントが実際のコードと同期したままになるか、コードが変更された場合に削除されるように注意する必要があります。明らかに、時期尚早な最適化に関する通常の警告も適用されます...


「明らかに、2つのバージョンが実際に同じことを行い、コメントが同期を保つように注意する必要があります...」-すぐに、これが良いアイデアではない理由を説明しました。
sleske

1
まあ、それはすべてのコメントの問題ですよね?一部のベクトル化されたコードは十分に不透明であるため、コメントは価値があり、「展開された」バージョンを持っているとデバッグに便利です。
マットクラウス14

本当です。それでも、私はコメントをできるだけ簡潔に保ち、完全なソースコードを使用しないようにします。とにかく、例を持っている場合、それを読みやすくするための最善の方法を尋ねるのは良い質問です(ここまたはcodereview.seで)。
sleske 14

1
最後のケースでは、両方のコードバリアントをコンパイル可能なコードとして保持します。
CodesInChaos

12

有用なコメントアウトされたコードを見たのは、すべてのオプションのコードが提供されている設定ファイルでしたが、コメントアウトされているため、コメントマーカーを削除するだけで簡単に設定を有効にできます。

## Enable support for mouse input:
# enable_mouse = true

この場合、コメント化されたコードは、利用可能なすべてのオプションとその使用方法を文書化するのに役立ちます。全体を通してデフォルト値を使用することも慣習的であるため、コードはデフォルト設定も文書化します。


7

一般的に、コードはコードを書いた人にのみ自己文書化されます。ドキュメントが必要な場合は、ドキュメントを書きます。ソースコードベースを初めて使用する開発者が何千行ものコードを読んで、何が起きているのかを把握しようとすることは期待できません。

この場合、コメントアウトされたコード行の目的は、重複するコードの2つのインスタンスの違いを示すことです。コメントを使用して違いを微妙に文書化する代わりに、コードが書き直されるようにしてください。次に、コードにコメントする必要があると感じたら、適切なコメントを書きます。


2
これは非常に真実です。多くの人々(私自身も含む)は、コードが非常に優れているため、ドキュメントを必要としないと考えています。しかし、世界中の誰もが、それが徹底的に文書化されコメントされていない限り、それがゴブルディグックであることに気づきます。
ライアンアモス

コードはコードを書いた人に自己文書化するだけです」-1年前に書いたコメントのない複雑なコードを選んで、限られた時間で理解してみてください。できないの?おっと。
JensG 14

私はそれがもう少し微妙だと思います。よく書かれたコードの多くはわかりやすく、コメントなしで理解できます。問題は、複雑な詳細だけを進めなければならないときに、全体像(かなりローカルなレベルであっても)を把握しようとすることです。コメントは非自明なコードの塊を説明するのに適していますが、適切なdocstringがあり、各関数、クラス、およびモジュールが実際に何のためにあるのかを説明する場合、実装を理解するのにそれほど助けは必要ありません。
カールスミス

4

いいえ、コメントされたコードは古くなり、価値のないものよりもすぐに悪くなります。現在のすべての仮定とともに、実装のいくつかの側面を固めるため、多くの場合有害です。

コメントには、インターフェイスの詳細と目的の機能を含める必要があります。「意図された機能」:最初にこれを試み、次にそれを試み、次にこのように失敗することを含めることができます。

私が見たプログラマーは、コメントに物事を残そうとしているので、完成した製品に何かを追加していなくても、自分が書いたものに夢中です。


2

非常にまれなケースである可能性がありますが、あなたがやったようにではありません。他の答えは、その理由をかなりうまくまとめています。

まれなケースの1つは、すべての新しいパッケージの開始点として、主に重要なものが残されていないことを確認するために、ショップで使用するテンプレートRPM仕様です。すべてではありませんが、ほとんどのパッケージには、標準名を持ち、タグで指定されたソースを含むtarballがあります。

Name:           foomatic
Version:        3.14
 ...
Source0:        %{name}-%{version}.tar.gz

ソースのないパッケージの場合、標準形式を維持するためにタグをコメントアウトし、その上に別のコメントを追加し、開発プロセスの一部として誰かが問題を止めて考えたことを示します。

Name:           barmatic
Version:        2.71
 ...
# This package has no sources.
# Source0:        %{name}-%{version}.tar.gz

他の人がカバーしているように、そこに属するものと間違われる可能性があるため、使用されないことがわかっているコードを追加しないでください。できる。ただし、コードの欠落が予想される理由を説明するコメントを追加すると便利です。

if ( condition ) {
  foo();
  // Under most other circumstances, we would do a bar() here, but
  // we can't because the quux isn't activated yet.  We might call
  // bletch() later to rectify the situation.
  baz();
}

5
おそらく、そのコメントはコードからコメントアウトされていません。
jk。

1
@jk:あなたは間違いなく正しいです。
Blrfl

1

コメントアウトされたコードはアプリケーションによって使用されないため、使用されない理由を示すコメントを追加する必要があります。ただし、そのコンテキスト内で、コメントアウトされたコードが役立つ場合があります。

私が思い浮かぶのは、一般的で魅力的なアプローチを使用して問題を解決する場合ですが、実際の問題の要件はその問題とわずかに異なることがわかります。特に、要件がかなり多くのコードを必要とすることが判明した場合、メンテナーが古いアプローチを使用してコードを「最適化」する誘惑は強いと思われますが、それを行うとバグが元に戻ります。コメントで「間違った」実装を維持することは、この状況でそのアプローチが間違っている理由を正確に説明するために使用できるため、これを解消するのに役立ちます。

これは非常に頻繁に発生することを想像できる状況ではありません。通常、サンプルの「間違った」実装を含めずに物事を説明すれば十分です。しかし、それだけでは不十分な場合想像できます。そのため、質問はそれが有用であるかどうかに関するものなので、そうです。ほとんどの場合ではありません。


1
申し訳ありませんが、コメントアウトコードの値が表示されません。コメントアウトされたコードは使用されないため、本番コードには配置されません。
ウラジミールコチャンチッチ14

1
「使用済み」を定義してください。
JensG 14

彼は「実行された」ことを意味したと思う
アレクシス・デュフレノイ

-2

これは相性が良くありません。

コメントされたコードは...ただのコードではありません。コードはロジックの実装用です。コード自体を読みやすくすることは芸術です。@CodesInChaosがすでに示唆しているように、コードの繰り返し行はロジックの実装としてはあまり良くありません

真のプログラマーは論理的な実装よりも読みやすさを好むと本当に思いますか?(ちなみに、論理表現に入れるコメントと「補数」があります)。

私の知る限り、コンパイラ用のコードを書く必要があります-それがいいのです-「それ」がそのコードを理解していれば。人間が読みやすいように、コメントは、開発者(長期的に)、そのコードを再利用する人々(テスターなど)に適しています。

そうでなければ、ここでもっと柔軟な何かを試すことができます。

boutique.setSite(site)は次のように置き換えることができます

setsiteof.boutique(site)。OOPには、読みやすさを向上させるさまざまな側面と視点があります。

このコードは最初は非常に魅力的であるように見えますが、人間が読みやすい方法を見つけた一方で、コンパイラーも完璧に機能していると考えることができます。時間の経過とともにさらに複雑になります。


15
「私が懸念している限り、コンパイラ用のコードを書く必要があります」ああ、しないでください。これが、難読化されたCコンテストなどから直接取り上げられるような怪物になってしまう方法です。コンピューターはバイナリですが、人間はファジーロジックを使用します(ちなみに、これはペットの飼い主には2倍になります)。プログラマーの時間は比較的非常に高価ですが、コンピューターの時間は今日ではほとんど無料です(基本的には単に電気の使用量)。人間向けのコードを書くと、コンパイラはそれを理解します。人間に関係なくコンパイラーのコードを書くと、チームで多くの友達を作ることはできません。
CVn

3
コンパイラ用のコードを書く」-実際にはそうしません。あなたが心に留めておくべき人は、あなたのコードを維持するためにタスクを引き継ぐ人です。
JensG 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.