ブール論理の保守性-ステートメントが必要な場合、ネストしますか?


11

これらのどれが保守性に優れていますか?

if (byteArrayVariable != null)
    if (byteArrayVariable .Length != 0)
         //Do something with byteArrayVariable 

または

if ((byteArrayVariable != null) && (byteArrayVariable.Length != 0))
  //Do something with byteArrayVariable 

私は2番目のものを読み書きすることを好みますが、そのようなことを行うと保守性が悪くなることを完全なコードで読んだことを思い出します。

これはif、最初の部分がfalseであり、すべての言語がそれを行うわけではない場合、2番目の部分を評価しないように言語に依存しているためです。(nullで評価された場合、2番目の部分は例外をスローしますbyteArrayVariable。)

それが本当に心配なのかどうかわからないので、質問に対する一般的なフィードバックをお願いします。

ありがとう。


1
最初の形式は、ダングリング、他の危険性を持っている
JBRWilkinson

好奇心が強い、あなたはどの言語で作業していますか?
STW

@STW-C#を使用し、Delphiにいくつかのレガシーコードがあります。
ヴァッカーノ

2
知っておくといい。私はDelphiに精通していませんが、C#では、短絡評価を実行する&&and ||演算子に自信を持つことができます。通常、ある言語から別の言語に移行するにはいくつかの落とし穴があり、それらの小さな問題をキャッチするためにコードレビューを行うことについてしっかりするのは良いことです。
STW

ここでは多くの回答とともに、2番目の方が読みやすくなっていますが、最初の方がはるかに簡単にデバッグできます。この場合、簡単にデバッグできることを確認しているので、私はまだ2番目を使用します。ただし、一般的に注意してください。
メイガス

回答:


30

2番目の形式は問題なく、あなたがやろうとしていることをより明確に表していると思います。あなたはそれを言う...

そのようなことを行うと保守性が悪くなることを完全なコードで読んだことを思い出します。これは、最初の部分がfalseであり、すべての言語がそれを行うわけではない場合、ifの2番目の部分を評価しないように言語に依存しているためです。

すべての言語がそれを行うかどうかは関係ありません。あなたにいる書き込み1つの特定の言語、その場合にのみ重要その言語がそれを行います。それ以外の場合、他の言語がそれらの機能をサポートしていない可能性があるため、特定の言語の機能を使用すべきではないと言っていることになります。


12
同意した。別の言語にコピーしたときにコードが同じように実行されるのであれば、なぜ私は気にするのでしょうか?
ティムグッドマン

16

私は誰もそれについて言及していないことに驚いています(そのため、私は質問を誤解していないことを願っています)- しかし、両方ともがっかりです!

より良い代替手段は、早期終了を使用することです(他のコードを実行する必要がない場合は、コードの早い段階でreturnステートメントを配置します)。これは、コードが比較的適切にリファクタリングされており、各メソッドに簡潔な目的があると仮定しています。

その時点で、次のようなことを行います。

if ((byteArrayVariable == null) || (byteArrayVariable.Length != 0)) {
  return; // nothing to be done, leaving
}

// Conditions met, do something

検証のように見えるかもしれませんが、まさにそれです。メソッドがそれを実行するための条件が満たされていることを検証します。提供されたオプションは両方とも、事前条件チェック内の実際のロジックを隠しました。

コードが大量のスパゲッティ(メソッドが長い、ロジックが散在する入れ子になったifなど)である場合は、小さなスタイルの問題の前にコードを形にするという大きな問題に焦点を当てる必要があります。環境や混乱の深刻度に応じて、役立つツールがいくつかあります(たとえば、Visual Studioには "抽出メソッド"リファクタリング機能があります)。


ジムが言及しているように、早期終了の構成方法についてはまだ議論の余地があります。上記の代替案は次のとおりです。

if (byteArrayVariable == null) 
  return; // nothing to be done, leaving

if (byteArrayVariable.Length != 0)
  return;

// Conditions met, do something

1
良いロジックをラップする代わりにリターンに同意しますが、同じ人々は||の使用について同じ議論を使用します。はどうかと言うと &&。
MIA

14

この条件以外のすべてについてトラップしようとして時間を無駄にしないでください。データまたは条件を失格にできる場合は、できるだけ早く失効させてください。

if (byteArrayVariable == null) Exit;
if (byteArrayVariable.Length == 0) Exit;
// do something

これにより、新しい条件に合わせてコードをはるかに簡単に調整できます

if (byteArrayVariable == null) Exit;
if (byteArrayVariable.Length == 0) Exit;
if (NewCondition == false) Exit;
if (NewerCondition == true) Exit;
// do something

2
+1うん、うん、うん。これほど単純なロジックは、難しいコードにはなりません。あなたの(アスカーの)内臓はあなたにこれを告げるべきです。
ジョブ

11

あなたの例は、ifsブール比較を適切にサポートするほとんどの言語にとってネストが悪いアプローチである理由の完璧な例です。ネストするとifs、意図がまったく明確でない状況が発生します。2番目ifが最初の直後に続くことが必要ですか?それとも、まだ別の操作を行っていないからですか?

if ((byteArrayVariable != null) && (byteArrayVariable.Length != 0))
  //Do something with byteArrayVariable 

この場合、これらはほとんど一緒になっている必要あります。これらは、例外が発生する操作を実行しないようにするためのガードとして機能しています。ネストされたを使用ifsすると、2つの部分が2つの部分からなるガードまたは他の分岐ロジックを表すかどうかについて、あなたをフォローしている人の解釈に任せます。それらを単一ifに結合することで、私はそれを述べています。あるべきではない場所に操作をこっそり入れることは、はるかに困難です。

私は、「すべての言語で動作しない」という愚かな主張よりも、常に自分の意図を明確に伝えることを好みます。推測してください... throwすべての言語でも動作しません。つまり、C#またはJavaでコーディングするときに使用しないで、代わりに問題が発生したときにシグナルを返すために戻り値に依存する必要がありますか?

とはいえ、STWが答えで述べているようにどちらかが満たされていない場合は、それを反転させてメソッドから抜け出す方がはるかに読みやすくなります。


3つ以上の条件は、nullを返す独自の関数を保証する場合があります。
仕事

3

この例では、2つの句が直接関連しているため、2番目の形式が適しています。

それらが関連していなかった場合(たとえば、さまざまな条件での一連のガード句)、1番目の形式を好みます(または、複合条件が実際に表すものを表す名前を持つメソッドをリファクタリングします)。


1

Delphiで作業する場合、最初の方法は一般に安全です。(指定された例では、ネストされたifを使用しても得られるものはあまりありません。)

Delphiでは、コンパイラスイッチを介して、ブール式が評価するか「短絡」するかを指定できます。方法#1(ネストされたif)を行うと、最初の節がtrueと評価された場合(および厳密にその後)にのみ、2番目の節が実行されることを保証できます。


1
Delphi開発の23年間で、「ブール値の完全評価」オプションを変更したことはありません。コードを他の場所に配送する場合、ユニットに{$ BOOLEVAL OFF}または{$ B-}を配置します。
ジェリー

私もダメ。私も常に範囲チェックを使用しています...しかし、他の人はそうではありません。ブール式で使用される関数で副作用を使用するべきはないため、おそらくパフォーマンスの観点を除いて、違いを生むべきではありません。でも、誰かがきっとそうするでしょう!
フランクシェラー

@ジェリー:同意した。完全な評価が必要な場合がある唯一の理由は、副作用です。条件付きの副作用は悪い考えです。
ローレンペクテル

ちょうど私のコメントを再読してください23年は13であるべきです!私はタルディスを持っていません
ゲリー

1

2番目のスタイルは、最初のテストがオブジェクトの生成である場合、2番目のテストを実行してエラーを出力するため、VBAで裏目に出ることがあります。常に最初の方法を使用するためにオブジェクト検証を処理するとき、私はVBAの習慣を身につけました。


2
VBAはひどい言語だからです
Falmarri

@Falmarri、それにはいくつかの恐ろしいことがあります(そしていくつかの良いこともあります)。私は自分の娘を持っている場合、私は多くのものを修正します。

2
短絡ブール評価の欠如は、何よりもレガシーなものです。なぜ彼らはそれで始めなかったのか分かりません。OrElseとAndAlsoのVB.NETの「修正」はちょっと面倒ですが、おそらく後方互換性を損なうことなくそれを処理する唯一のオプションです。
JohnFx

1

特に、各句の周りに{}ブロックを使用している場合、2番目の形式は読みやすくなります。最初の形式では、ネストされた{}ブロックと複数レベルのインデントが発生するためです。各ブロックの終了位置を把握するため)。


0

どちらも読みやすいと思いますが、言語を切り替える場合はコードの保守性について心配するべきだという議論を受け入れません。

一部の言語では、2番目のオプションの方がパフォーマンスが高いため、その場合は明確な選択になります。


0

同感です; 私はそれを第二の方法で行います。私にとって、それは論理的に明確です。私の人生では「一部の言語」で実行されるプログラムを書いたことがないので、一部の言語が2番目の部分を偽と評価したとしても2番目の部分を実行するという懸念は少し愚かなように思えます。私のコードは常に特定の言語で存在しているように見えますが、それはその構造を処理できるかできないかのどちらかです。(そして、特定の言語がそれを処理できるかどうかわからない場合、それは私が本当に学ぶ必要があるものですよね。)

私の考えでは、最初の方法の危険性は、意図してifいないときに、そのネストされたブロックの外側に誤ってコードを入れることに対して脆弱になることです。確かに、これは大きな関心事ではありませんが、私のコードが言語に依存しないかどうかを心配するよりも合理的です。


0

読みやすいので、2番目のオプションを好みます。

実装しているロジックがより複雑な場合(文字列がnullではなく、空ではないことを確認することが単なる例です)、有用なリファクタリングを行うことができます。ブール関数を抽出します。「コード完了」のコメントで@mipadiと一緒にいます(「すべての言語がそれを行うかどうかは関係ありません...」)コードの読者が抽出された関数の内部を見ることに興味がない場合、ブール値のオペランドが評価されると、それらに対する論争の余地のある質問になります。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.