ELSEの悪いプログラミングを使用していますか?[閉まっている]


18

ELSEコンストラクトを使用することによって引き起こされるバグに頻繁に出くわします。主な例は、次のようなものです。

If (passwordCheck() == false){
    displayMessage();
}else{
    letThemIn();
}

私にとってこれはセキュリティの問題を叫ぶ。passwordCheckがブール値である可能性が高いことは知っていますが、アプリケーションのセキュリティを設定しません。その文字列、intなどの場合はどうなりますか?

私は通常ELSE、の使用を避けようとし、代わりに2つの完全に独立したIFステートメントを選択して、期待するものをテストします。それ以外はすべて無視されるか、具体的に処理されます。

確かに、これはアプリに入るバグ/セキュリティ問題を防ぐためのより良い方法です。

どうやってやるの?


3
あなたにとってセキュリティ上の問題は何ですか?「passwordCheck」とはどういう意味ですか?パスワードの確認はありましたか?パスワードの確認が必要ですか?ユーザーは合格しましたか?ユーザーは正しいパスワードを入力できませんでしたか?
LennyProgrammers

20
I know that passwordCheck is likely to be a boolean...どういう意味ですか?強い型付けされた言語。passwordCheck何だろうあなたはそれになりたいです。
ボビー

31
私は悪いインデントの慣行が使用するよりもエラーにつながると思いますelse...文を
gablin

15
これは奇妙に思えます。最初に、passwordCheck()ブール値でない可能性のある戻り値のタイプについて文句を言います(これは合理的な懸念かもしれません)else。どのような問題がelse原因なのかわかりません。
デビッドソーンリー

8
うーん、elseを使うのは悪いプログラミングかと尋ねるのは悪いプログラミングだと思います
Muad'Dib

回答:


90

elseブロックは常に、あなたがデフォルトの動作になりたい何で構成する必要があります。

それらを避ける必要はありません。適切に使用するよう注意してください。

あなたの例では、デフォルトの状態はアクセスを許可しないことです。少しリファクタリングすると、次のことができます。

If (passwordCheck)
{
   letThemIn();
}
else
{
   displayMessage();
}

すなわち、パスワードチェックが機能する場合、それらを入れてください。そうでなければ、何らかのエラーメッセージを表示することは常に有効です。

もちろんelse if、完全に別個のifステートメントではなく、使用することにより、ロジックにチェックを追加できます。


2
例のコンテキストで@ dave.b、それはセキュリティ上の問題になると思いますが、これがあなたが見ているコードベースの至る所にある場合、それはもう少しそれを必要とする人が書いた人の兆候です練習:)
RYFN

9
誰かがこれのセキュリティ面について詳しく説明できますか?if(!something){do a} else {do b}とif(something){do b} else {do a}は論理的に同等ですか?私はこれのセキュリティの点で違いが何であるかを理解しようとしていますか?
クリス

11
@Chris:OPは弱い型付けの言語を使用していると思います。したがってpasswordCheck、fe nullになります。fe は、内部エラーのためにレンダリングさpasswordCheck == falsefalse、ユーザーがログインを許可します。
ボビー

1
@クリス、私の理解では、デフォルトの状態はアクセスを許可することでしたが、必ずしもお勧めではありません。
RYFN

3
はい、これは言語に大きく依存しています。C#ではif必要でbool、変数は間違いなく私が何らかの理由での順番を考えることはできません、すべてのパスはなど、値を返す必要があり、割り当てられなければならないifelse読みやすさのほかにも問題でしょう。つまり、if(a){b();}{c();}と同等である必要がありますif(!a){c();{b();}。JavaScriptでは、他の一方で、あなたはそれを認識する必要がありpasswordCheckかもしれないundefinedなど、
ティム・グッドマン

57

いいえ、問題はありませんELSEELSEは新しいものではありませんGOTO。実際、IF代わりに2を使用ELSEすると、いくつかの問題が発生する可能性があります。

例1:

if (this(is(a(very())==complex(check())))) {
   doSomething();
}

if (!this(is(a(very())==complex(check())))) {
   doTheOtherThing();
}

コピーペーストが表示されますか?片方を変更してもう片方を忘れる日を待つだけです。

例2:

foreach(x in y) {
  if (first_time) {
    first_time = false;
    doSomething();
  }

  if (!first_time) {
    doTheOtherThing();
  }
}

ご覧のとおりIF、条件がすでに変更されているため、最初のアイテムに対して2番目のアイテムも実行されます。実際のプログラムでは、このようなバグを見つけるのは困難です。


12
私はこれに賛同する。コピー&ペーストifの文を、ちょうど避けるために、その論理式を反転else-今、それは悪いプログラミングです!だけでなく、あなたがコード(複製されている悪い -プログラミング)を、あなたもチェックが本当に複雑になっている場合、あなたは今、それを2回やっている(パフォーマンスを遅くしているba--ええと、まあ、あなたは彼らは時期尚早の最適化について言うことを知っています最近では... あまり良いプログラミングではありません!)。
ギャブリン

チェックは、独自の方法でなければなりません場合は、真/偽のを返すようにすることを正直に言うと
billy.bob

良い例です。2ifチェックとelseペアを使用した場合の1を使用した場合のパフォーマンスを忘れないでください。if / elseを使用するほとんどの言語では、not on条件を使用するifステートメントを2つ使用するよりもパフォーマンスが向上すると想定します。
クリス

1
dave.b:確かに、しかしそれは単純に始まりゆっくり成長するかもしれません。私の例の複雑なチェックは、問題をより明確にするためにここにあります。
user281377

3
うん-そして、条件はほとんどの言語で副作用を引き起こす可能性があることを忘れないでください、そして条件に機能がある場合、あなたは本当に見ることによって伝えることができません。
デビッドソーンリー

18

ELSEが常にあります。書くなら

if(foo)
  bar();

あなたは実際に書く

if(foo)
{
  bar();
}
else
{
   // do nothing
}

ELSE-pathに入れるものは何でもあなたの責任です。


7
-1。この答えはばかげすぎです。私はそうではないと言っているわけではありません。ポイントを逃しているだけです。どのようなコンパイルは、コードから生成することはあなたが書いたコーディング慣行やバグとは何の関係もありません

3
質問は「ELSEの悪いプログラミングを使用していますか?」でした。私の答えは、そこにいないふりをすることはできますが、避けることはできません。
LennyProgrammers

5
何語 ?Javaでは、その他はバイトコードにありません:P
IAdapter

@ acidzombie24-「その他」がどんな質問からのものであるかを考慮することは非常に良い習慣です。時々それはただです-機能で他のすべてを行いますが、それについてあなたが考えたことを示しています
マーティンベケット

14

個人的にはelseできる限り避ける傾向がありますが、セキュリティ上の問題のためではありません。

コードを読み取るとき、ネストされたステートメントは、どの条件のセットがそこにつながるかを覚えておく必要があるため、ロジックに従うことが難しくなります。このため、私は早期終了の大ファンです。

if (checkPassword != OK) { displayMessage(); return; }

letThemIn();

これもに適用forし、while私が使用するするループcontinuebreak、それは、インデントのレベルを回避するたびに。

Chris Lattnerは、LLVM Coding Standardsで行うよりも優れていると言います。


同意する。「その他」は精神的な「フォーク」を作成し、私たち人間は連続した生き物です。
user187291

ちなみに、これはガード条件と呼ばれています
CaffGeek

@Chad:ああ、ありがとう、いつも物事の名前を取得してくれてうれしい:)
マシューM.

1
+1。これは、スコアが1を超える唯一の答えです。*writes an answer*

私はそういうものとして他を避けようとはしませんが、あなたが書いたことに同意すると思います。ポイントは、テストするものは例外であり、通常のケースではないことです(stackoverflow.com/questions/114342/…)。ここで、認証の失敗は例外であり、(のみ)テストする必要があります。
hlovdal

5

次に、それらを交換します。

If (passwordCheck == true)
{
     letThemIn();
}
else
{
     displayMessage();
}

21
どうIf ((passwordCheck == true) == true)?:-)
カバ

1
読みやすさを向上させるのは私のスタイルです。if(!value)を書くことができますが、私はif(value!= true)を好む
アフメトカクシ

7
読みやすさは向上しません。ノイズを追加するだけです。さらに悪いことに、ブール演算子が怖いという理由だけでネストされたifコンストラクトを書くプログラマーもいます。
ak2

3
変数名が説明的なものである場合、理由はありません:if(someBooleanValue == true)が必要です。これは良いでしょう:if(validPassword){...
マークフリードマン

さて、質問内のコードブロックを置き換えただけです。あなたが私の最初のコメントを読んだ場合、私はif(!value)の代わりにif(value!= true)を使うことを好むと言いました。if(value)とif(!value)の違いがわかるといいですね。私は補数演算子を使用しないことを意味しました。それ以外の場合は、trueはtrueを意味します。
アフメットカクシ

3

Matthieu M.のように、深くネストされたelseブロックよりも早期に終了することを好みます。多くの人々が私たちに反対し、独自の出口を好むでしょう。それは議論のポイントではない(私は思う)。

今、私はelseそれが理にかなっているとき、特に単純で短い代替品のために確かに使用します。前述のように、テストの複製は時間の浪費であり(プログラマーとCPU)、混乱の原因であり、後にバグ(一方が変更され、他方が変更されない場合)の原因となります。
いつか、そのelse部分にコメントを追加して、条件が何であったか(特にif、たとえばレガシーコードのように部分が長い場合)または代替手段を思い出させます。

関数型プログラミングの極端な支持者の中にはif、パターンマッチングを優先して、完全に削除することを提案しているものがあることに注意してください。:-)


1
サイドノートとして:純粋な関数型言語にif構造体がある場合、本当にelseが必要です。すべての式は何かを返す必要があります!
トックランド

2

ELSEの使用に問題はありません。ただし、コードの読み取りと理解が非常に複雑になる可能性があります。悪いデザインを示している可能性があります。確かに、テストする必要がある追加のユースケースを示しています。

可能であればELSEを削除してみてください-しかし、それについては妄想しないでください。Steve McConnellは、この完全なコードをCode Completeで呼び出します。つまり、コードには単純で明確なパスがあります。

特定の問題を解決する方法:

  • ポリモーフィズムを使用します。システムの境界で、ユーザーのセキュリティ資格情報を検証します。それらが正当なものであれば、システムの関連部分へのアクセス権を持つセッションオブジェクトを返すか、例外をスローします。ただし、これによりシステムがより複雑になる可能性があります。したがって、理解しやすく保守しやすいものを決定します。

一般的に、次はコード内のELSEを削減するのに役立ちます。

  • 適切な要件があると、コードでのそのような決定の必要性が減る場合があります。ユースケース(その他)を実装する必要はまったくありません。
  • より明確な設計。最大の凝集力と最小限の結合。これにより、コンポーネントが他のコンポーネントで行われた決定を複製しないようにします。
  • エラーケースを管理するための例外処理。
  • ポリモーフィズム(上記の例を参照)。
  • switchステートメント-これらはELSEの美化されたものですが、特定の状況ではより優れています。

2
また、「複雑なブール値チェックを別の関数に移動する」も含めます。
ギャブリン

2

コードがセキュリティリークであるという仮定は、使用している言語によって異なる場合があります。Cコードでは問題になる可能性があります(特にCではブール値がゼロまたはゼロ以外のintであるため)。しかし、最も強く型付けされた言語(つまり、実行時型チェック)では、passwordCheck変数がブール値として宣言された場合、他に何かを割り当てる方法はありません。実際、ifブール演算子を使用するか、単に値を使用するかにかかわらず、述語のすべてがブールに解決される必要があります。passwordCheckランタイムにバインドされた別のタイプのオブジェクトがある場合、何らかのタイプの不正なキャスト例外がスローされます。

単純なif / elseコンストラクトはif / ifコンストラクトよりも読みやすく、誰かがコンストラクトを反転させようとした場合に不注意な問題が発生しにくくなります。同じ例を少し見てみましょう。

if(passwordCheck == false) {
    denyAccess();
}

if(passwordCheck) {
    letThemIn();
}

上記で実行する相互排他句の意味は失われます。それがif / elseコンストラクトが伝えるものです。相互に排他的な2つの実行ブランチ。1つは常に実行されます。これはセキュリティの重要な部分letThemInです。-を呼び出した後は、方法がありませんdenyAccess

コードを明確にするため、および重要なセクションが最も保護されていることを確認するために、それらはプライマリ句(ifパート)内にある必要があります。デフォルトの非準拠の動作は、代替句(elseパート)にある必要があります。例えば:

if(passwordCheck) {
    letThemIn();
} else {
    denyAccess();
}

注:さまざまな言語で作業する際に、「文字列ならどうなるのか?」という質問を避けるのに役立つコーディング習慣を開発しました。基本的に、定数をブール式に最初に入れることです。たとえば、チェックする代わりに、passwordCheck == false私はチェックしていfalse == passwordCheckます。これにより、C ++で起こりうる偶発的な割り当ての問題も回避できます。このアプローチを使用すると、コンパイラはの=代わりに入力すると文句を言い==ます。JavaやC#などの言語では、コンパイラはif句の割り当てをエラーとして扱いますが、C ++は喜んで受け入れます。だから、私もnull最初にnullチェックを行う傾向があります。

言語を定期的に変更する場合は、定数を最初に配置すると非常に役立ちます。ただし、私のチームではコーディング標準とは反対であり、コンパイラはとにかくこれらの問題をキャッチします。破るのは難しい習慣になります。


1

elseプログラミング時に使うのが悪いとotherwise言うのは、話すときに使うのは悪いと言うようなものです。

確かに、それらは両方とも悪い方法で使用することができますが、それはあなたがそれらを含むために起こった間違いを犯したという理由だけでそれらが回避されるべきであることを意味しません。多くのバグdefaultswitchステートメント内の欠落したケースに依存していても、私は驚かないでしょう。


1

Elseアプリケーションフローをホワイトリストに登録すると考えてください。アプリケーションフローの続行を許可する必要がある条件を確認し、これらの条件が満たされない場合はElse、問題を解決するか、アプリケーションの実行を中止するか、または同様のものを実行します。

Else それ自体は悪くはありませんが、それをうまく使用しないと、望ましくない効果を見ることができます。

また、についてのあなたの声明に関して

「passwordCheckがブール値である可能性が高いことは知っていますが、アプリケーションのセキュリティをそれにしません。」

開発するメソッドの場合、常に1つのデータ型が返されます。PHP Coreには2つ以上のデータ型を返すコードが散らばっていますが、これは関数呼び出しの推測を行うため、悪い習慣です。複数のデータ型を返す必要がある場合は、例外をスローすることを検討してください(これが別のデータ型を返す理由であることがよくあります-何かが恐ろしく、恐ろしく間違っていました)、またはコードを再構築して1つのデータ型のみを返します。


複数のデータ型を返す言語があることを知りませんでした!ポリモーフィック関数を参照していますか?関数をオーバーロードするたびに、常に同じデータ型が返されますが、異なる引数を取る場合があります。
マイケルK

1
緩やかに型付けされた言語、特にPHPでは、関数は複数のデータ型を返すことができます。例えば:stristr-「マッチした部分文字列を返し針が見つからない場合は、返すFALSE。」
Craige

@ Michael、PHP関数は必要なものをすべて返すことができます。データ型に制限はありません。私の最も複雑な関数はtrue / false / nullを返しますが、true / integer / null / string / float / arrayを返す関数の作成を止めることはありません(常識を除いて)。
TRiG

面白い。PHPを使用したことはありません。しかし、説明をありがとう-おそらく将来的に私を助けて!Javascriptのようなものですか?
マイケルK

@Michael-Javascriptに非常によく似ています。
クレイジュ

1

まず第一に。笑!他を避ける理由はまったくありません。形や形を問わず、決して悪い習慣ではありません。

何かあれば、コードは

if(!IsLoggedIn) { ShowBadLoginOrNoAccessPage(); return }

そこに2つのifsはなく、他にありません。これは、例外をスローするものを除くすべてのアプリで行うことです。例外は、表示する適切なページのURLをチェックする関数でキャッチされます(または、asp.netエラー関数にキャッチ/チェックを入れることができます)。許可しない、または例外で使用するすべてのメッセージを示す汎用ページを出力します(例外のタイプを常にチェックし、httpステータスコードを設定します)。

-編集-ammoQの例にあるように、2つのifsはばかげています。本当に elseはifと同じかそれ以上です。ifsを回避する必要がある場合(個人的にはいけませんが、リターンを使用し、頻繁にブレークします)、より多くのコードパスがバグの可能性を高めると言われています。循環的複雑度を参照

-Edit 2- if / elseの使用法が心配な場合。また、次のように一番短いコードブロックを一番上に置くことが私の好みであることにも注意してください。

if(cond == false) {
    a()
    b()
    c()
    onetwothree()
}
else
{
    a()
    b()
    c()
    more()
    onetwothree()
    code()
    longer()
}

むしろその後

if(cond) 
{
    a()
    b()
    c()
    more()
    onetwothree()
    code()
    longer()
}
else
{
    a()
    b()
    c()
    onetwothree()
}

0

可能な場合、条件の前にデフォルトを設定するのが好きです。私はそれが少し読みやすく、もう少しはっきりしているように感じますが、これは単なる好みです。私は自分のコードでマイナス条件を回避しようとする傾向があります。私は!fooまたはfalse == fooをチェックすることを大したファンではありません。

foo = bar;

if ('fubar' == baz) {
    foo = baz;
}

の代わりに ...

if ('fubar' == baz) {
    foo = baz;
} else {
    foo = bar;
}

前のコードブロックは、私にとって読みやすいように思えます。私のコードについて一種の懐疑的な妄想を持つことは、私にとってより自然に思えます。条件に関係なくデフォルトを設定すると、快適に感じることができます:P


0

私は、あらゆる種類の分岐ロジックの使用を可能な限り避けるべきだと主張します。ELSEやIFには何も問題はありませんが、分岐ロジックを使用する必要性を最小限に抑えるためのコードを記述する方法はたくさんあります。分岐ロジックは完全に排除できるとは言っていません-一部の場所で必要になりますが、コードのリファクタリングを行ってそのかなりの部分を排除することは可能です。ほとんどの場合、これによりコードの明瞭度と精度が向上します。

一例として、三項演算子も通常は適切な候補です。

If VIP Then 
  Discount = .25
Else
  Discount = 0
End If
Total = (1 - Discount) * Total

三項アプローチの使用:

Discount = VIP ? .25 : 0
Total = (1 - Discount) * Total

三項演算子は、分岐を適切な方法で右にシフトします。

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