web-dev-qa-db-ja.com

ボブおじさんが「役に立たないかっこ」を取り除くのが好きなことに挑戦することはできますか?

ペイウォールコンテンツを参照するのは嫌いですが、- このビデオ は、私が話していることを正確に示しています。ロバートマーティンでの正確な12分はこれを見ます:

Some code

そして、「私の好きなことの1つは、無駄な中括弧を取り除くことです」と彼はそれを次のように変えています:

More code

昔、遠く離れた教育機関では、ifで制御されていない場合にインデントされた行を追加してバグを簡単に追加できるため、これを行わないように教えられました。

ボブおじさんに公平を期すために、彼は長いJavaメソッドを、私が同意する、はるかに読みやすい小さな小さな関数にリファクタリングしています。彼がそれを変更し終えると、(22.18)このようになります。 :

Yet more code

それが中括弧の削除を検証することになっているのだろうかと思います。私はすでに ベストプラクティス に精通しています。この点でボブおじさんに挑戦できますか?ボブおじさんはその考えを擁護しましたか?

96
candied_orange

読みやすさは小さなことではありません。

単一のメソッドを囲むブレースに関しては、私は複雑な考えを持っています。単一行のreturnステートメントなどの場合は、個人的に削除しますが、そのような中かっこを省略すると、実際に最後に作業した場所で私たちを一生懸命噛みました。誰かがifステートメントにコードを追加しましたが、必要な中括弧も追加していませんでした。Cであるため、警告なしにシステムがクラッシュしました。

その小さな大失敗の後、常にブレースを使用することについて信心深い人には決して挑戦しません。

読みやすさのメリットはあると思いますが、中かっこを省略したときに発生する可能性のある問題を痛感しています。

私は、研究や誰かの公開された意見を見つけようとする気になりません。誰もが1つ(意見、つまり)を持っていて、それは文体の問題なので、1つの意見は他の意見と同じくらい良いです。問題を自分で考え、長所と短所を評価し、自分ののろわれた心を作り上げてください。あなたが働いている店がこの問題をカバーするコーディング標準を持っているなら、それに従ってください。

48
Robert Harvey

here または here で、または自転車の小屋が塗装されている場所では、ノーブレーススタイルのいくつかの公開されたプロモーションまたは拒否を見つけることができます。

バイクの小屋から離れて、2014年の素晴らしいOS X/iOS SSLバグを覚えていますか?

_if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
    goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;
_

うん、ノーブレースブロックによって「引き起こされた」 https://www.imperialviolet.org/2014/02/22/applebug.html

好みはブレースのスタイルに依存するかもしれません。私が書かなければならなかった場合

_if (suiteSetup)
{
    includePage(mode, suiteSetup);
}
_

スペースも節約したいと思うかもしれません。だが

_if (suiteSetup) {
    includePage(mode, suiteSetup);
}
_

「追加」の行を1つだけ使用します。


私はあなたが尋ねなかったのを知っています、しかし私が一人で働いているなら、私は異端者です。ブレースを削除する場合、私は好む

_if (suiteSetup != null) includePage(mode, suiteSetup);
_

IOSのSSLスタイルのバグと同じ視覚的な問題はありませんが、ボブおじさんよりも「不要な」行が節約されます;)慣れていればよく読み、Ruby(includePage(mode, suiteSetup) unless suiteSetup.nil?)ええと、たくさんの意見があることを知ってください。

131
Paul Draper

ボブおじさんは、「常に中かっこを使用する」が主流の知恵であったとき、それほど一般的ではなかったそのような間違いに対する多くの防御層を持っています。

  1. 単一行の条件文に対する個人の強い好み。そのため、複数行の条件文が目立ち、細かく調べられます。
  2. 2行目を挿入すると自動的にインデントを解除するエディター。
  3. 彼が常に実行している完全な単体テストスイート。
  4. 統合テストの完全なスイート。
  5. 彼のコードがマージされる前に行われたピアレビュー。
  6. 継続的インテグレーションサーバーによるすべてのテストの再実行。
  7. 製品の品質部門によって行われたテスト。

ボブおじさんにチャレンジを公開した場合、彼は上記の点についてかなり良い反論をするでしょう。これは、早期に発見する最も簡単な間違いの1つです。

60
Karl Bielefeldt

ほとんどの場合、これは個人的な好みですが、考慮すべき点がいくつかあります。

考えられるバグ

中括弧を忘れることによって引き起こされるバグはまれであると主張できますが、私がseenから- それ彼ら行うhappenときどき (有名な IOS goto fail バグを忘れないでください)。だから私はあなたのコードスタイルを考えるときこれが要因だと思います(いくつかのツールは misleading-indentation について警告するので、それはあなたのツールチェーンにも依存します)

有効なコード(それはそのように読みますバグかもしれません

あなたのプロジェクトがそのようなバグに苦しんでいないと仮定しても、コードを読むとき、それらはバグのように見えるコードのブロックを見るかもしれませんバグである可能性があります-しかし、そうではありませんあなたの精神サイクル。

まずは次のとおりです。

_if (foo)
    bar();
_

開発者が役立つコメントを追加します。

_if (foo)
    // At this point we know foo is valid.
    bar();
_

その後、開発者はそれを拡張します。

_if (foo)
    // At this point we know foo is valid.
    // This never fails but is too slow even for debug, so keep disabled.
    // assert(is_valid(foo));
    bar();
_

または、ネストされたブロックを追加します。

_if (foo)
    while (i--) {
        bar(i);
        baz(i);
    }
_

またはマクロを使用します:

_if (foo)
    SOME_MACRO();
_

"...マクロは複数行のコードを定義する可能性があるため、マクロはdo {...} while (0)を複数行に使用しますか?これは、スタイルガイドにあるためです。場合!"


上記の例はすべて有効なコードですが、コードブロックのコンテンツが多いほど、間違いがないことを確認するために読む必要があります。

多分あなたのコードスタイルは複数行のブロックが中括弧を必要とすることを定義します(たとえそれがコードでなくても)、しかし私はこれらの種類のコメントが量産コードに追加されました。あなたがそれを読んだとき、それらの行を最後に編集した人がブレースを追加するのを忘れたという小さな疑問があります、時々私はダブルチェックの必要性が意図したように機能していると感じます(特にこれのバグを調査するとき)コードの領域)

異音

単一線に中括弧を使用する1つの実用的な理由は、diffノイズを減らすことです。

つまり、変更:

_if (foo)
    bar();
_

に:

_if (foo) {
    bar();
    baz();
}
_

...条件付きラインが変更されたときに差分として表示されます。これにより、小さいが不必要なオーバーヘッドが追加されます。

  • コードレビューで行が変更されているように見えます。比較ツールがWordベースの場合は、中かっこのみが変更されていることが簡単にわかりますが、行がまったく変更されていないかどうかを確認するにはさらに時間がかかります。
    それでも、すべてのツールがWordベースの差分をサポートしているわけではなく、diff(svn、git、hg ...など)は、高級なツールであっても行全体が変更されたかのように表示されます。何が変更されたかを確認するには、プレーンラインベースのdiffを調べます。
  • 注釈ツール(_git blame_など)は、変更された行を表示し、realの変更を見つけるために、行の原点の追跡をさらにステップにします。

これらはどちらも小さく、変更されたコード行をコミットするコードレビューまたはトラッキングダウンに費やす時間に依存します。

Diffで追加の行を変更することのより具体的な不便さ、コードの変更により競合が発生し、マージして手動で解決する必要がある競合が発生する可能性が高い


これには例外があり、独自の行に_{_があるコードベースの場合、これは問題ではありません。

このスタイルで記述した場合、diff noise引数は保持されません。

_if (foo)
{
    bar();
    baz();
}
_

ただし、これはそれほど一般的な慣習ではないため、完全を期すために回答に主に追加します(プロジェクトがこのスタイルを使用することを示唆していません)

32
ideasman42

数年前、私はいくつかのCコードをデバッグするために連れてこられました。バグを見つけるのは非常に困難でしたが、最終的には次のようなステートメントに要約されます。

if (debug)
   foo (4);

そして、それを書いた人がfooをマクロとして定義していることがわかりました。 twoのコード行が含まれるマクロ。そしてもちろん、これらの2行のうち最初の行だけがifの対象でした。 (したがって、2行目は無条件に実行されました。)

これはCとそのプリプロセッサ(コンパイル前に置換を行う)に完全に固有のものである可能性がありますが、私はそれを忘れたことはありません。そのようなことはあなたに痕跡を残します、そしてそれを安全にプレイしてみませんか?特にあなたがさまざまな言語とツールチェーンを使用していて、そのような悪意が他の場所では不可能であると確信できないなら?

今、私は括弧をインデントして他の人とは違って使用しているようです。単一行ifの場合、次のようにします。

if (debug) { foo (4); }

そのため、中括弧を含めるための追加の行は必要ありません。

15
Wayne

「ボブおじさん」は彼の意見を持つことができ、あなたはあなたの意見を持つことができます。彼に挑戦する必要はありません。

権威に訴えたい場合は、Chris Lattnerに相談してください。 Swiftでは、ifステートメントは括弧を失いましたが、常に中括弧が付いています。議論はありません、それは言語の一部です。したがって、「Uncle Bob」が中括弧を削除し始めると、コードはコンパイルを停止します。

他の誰かのコードに目を通し、「無用な中括弧を取り除く」のは悪い習慣です。コードのレビューが必要な場合、および不必要に競合が発生した場合にのみ、余分な作業が発生します。多分「ボブおじさん」はコードレビューが必要ないほど信じられないほど優秀なプログラマーですか?トッププログラマーの1人がコードレビューなしで "if(p!= NULL)"を "if(!p)"に変更し、可能な限り最悪の場所に隠れたため、1週間を無駄に費やしました。

これはほとんど無害なスタイルの議論です。中括弧には、中括弧を追加せずに別のコード行を挿入できるという利点があります。ロギングステートメントまたはコメントのように(コメントの後にステートメントが続く場合は、ひどいです)。同じ行にあるステートメントには、多くのデバッガーで問題が発生するという実用上の欠点があります。しかし、好きなようにしてください。

15
gnasher729

ブレースを削除しない理由は次のとおりです。

  1. 意思決定の疲労を減らします。中括弧を常に使用する場合、中括弧が必要かどうかを決める必要はありません。

  2. 開発ドラッグを減らす:最終的にに努力しても、ロジックのすべての複数行をメソッドに抽出します。したがって、中括弧を削除する作業と、さらにコードが必要になったときに再度追加する作業があります。小さいですが、迷惑です。

9

若い同僚は、私たちが冗長で不必要であると考えるブレースが実際に彼に役立つと言っています。正確な理由は思い出せませんが、もし彼がより良いコードをより速く書くことができるなら、それだけがそれらを維持する理由です。

Fwiw、私たちはそれらを1行に置くことでそのような短い前提条件unが読めない/気を散らすことができないという妥協に同意しました。例えば。

if (!param) { throw invalid_argument (blahblah); }
if (n < 2) { return 0; }
// real code for function starts here...

これらの導入の前提条件は、多くの場合、本文の制御フローステートメント(例:return)であるため、同じ条件にあることを意図した2番目のステートメントを追加し、中括弧を書くのを忘れる恐れは悲惨です。 。条件付きの2番目のステートメントは、いずれにしてもデッドコードであり、意味がありません。

読み取りの流暢さの問題は、条件付きステートメントの一部として中かっこを使用するように配線されている人の脳パーサーが原因であると思います。これはC++の文法を正確に表したものではありませんが、特定のother言語を最初に学習することの副作用である可能性があります。

0
JDługosz