開発者は、ステートメントに否定条件を含めるべきではなく、常にelseブロックを用意する必要がある場合、


169

私には知り合いがいて、私よりもベテランの開発者です。私たちはプログラミングの実践について話していましたが、「if」ステートメントに関する彼のアプローチには驚かされました。彼は、私がかなり奇妙だと思うifステートメントに関するいくつかの慣行を主張しています。

まず、ifステートメントの後にelseステートメントを続ける必要があります。挿入するものがあるかどうかは関係ありません。次のようなコードになります。

if(condition) 
{
    doStuff();
    return whatever;
}
else
{
}

第二に、偽よりも真の値をテストする方が良いです。つまり、「!doorOpened」変数の代わりに「doorClosed」変数をテストする方がよいということです。

彼の議論は、コードが何をしているのかを明確にするということです。

これら2つのルールを組み合わせることで、条件が満たされていないときに何かを実行したい場合、この種のコードを書くようになる可能性があるため、かなり混乱しています。

if(condition)
{
}
else
{
    doStuff();
    return whatever;
}

これについての私の考えは、それは実際には非常にいことである、および/または品質改善があったとしてもごくわずかであるということです。しかし、私は後輩として、本能を疑う傾向があります。

だから私の質問は次のとおりです。それは良い/悪い/「問題ではない」プラクティスですか?それは一般的な習慣ですか?



57
あなたの同僚は、生命と手足が危険にさらされるかもしれない背景から来ている可能性はありますか?私は、コードで非常に多くのテストと自動分析が行われ、それを間違えると文字通り誰かの命を奪う可能性があるシステムで、この種のことについていくつか言及していると思います。
jpmc26

11
あなたの会社のコードスタイルガイドは何と言っていますか?
トールビョールンラヴンアンデルセン

4
「2番目に」質問に対する部分的な回答。アクションブロックの1つが長く、もう1つが短い場合、短いブロックを最初に置く条件をテストします。これにより、コードを読み取るときに見逃される可能性が低くなります。その条件は否定かもしれませんし、trueのテストにするために名前を変更することもできます。
イーサンボルカー

9
Resharperは、「あなたのコードは冗長で役に立たないので、それを削除/リファクタリングしてほしいですか?」という行に沿って、友人に伝えるものがあります。
BgrWorker

回答:


184

明示的なelseブロック

最初のルールはコードを汚染するだけで、コードを読みやすくしたり、エラーを起こしにくくしたりしません。あなたの同僚の目標は-私はそう思う-開発者が条件がに評価されるかもしれないことを完全に認識していることを示すことによって、明示的であることfalseです。明示的であることは良いことですが、そのような明示性は3行の余分なコードを犠牲にしてはいけません

ifステートメントの後に必ずしもelse1つも何も続かないという事実すら言及していません。1つ以上elifのs が続くこともあります。

returnステートメントの存在は事態を悪化させます。elseブロック内で実行するコードが実際にあったとしても、次のようにすると読みやすくなります。

if (something)
{
    doStuff();
    return whatever;
}

doOtherThings();
return somethingElse;

これにより、コードの行数が2行少なくなり、elseブロックが妨げられなくなります。ガード条項はそれに関するすべてです。

ただし、同僚の手法により、スペースのないスタックされた条件ブロックの非常に厄介なパターンを部分的に解決できることに注意してください。

if (something)
{
}
if (other)
{
}
else
{
}

前のコードでは、最初のifブロックの後に正常な改行がないため、コードを誤解しやすくなります。ただし、同僚のルールによりコードの誤読が難しくなりますが、簡単な解決策は単に改行を追加することです。

テスト用trueではないため、false

2番目の規則は意味をなすかもしれませんが、現在の形式ではそうではありません。

閉じたドアのテストが、開いていないドアのテストよりも直感的であることは間違いではありません。否定、特にネストされた否定は、通常理解が困難です。

if (!this.IsMaster || (!this.Ready && !this.CanWrite))

それを解決するには、空のブロックを追加する代わりに、関連する場合は追加のプロパティ、またはローカル変数を作成します

上記の条件は、かなり簡単に読み取り可能にすることができます。

if (this.IsSlave || (this.Synchronizing && this.ReadOnly))

169
空のブロックは常に間違いのように見えます。それはすぐに私の注意を引き付け、「なぜこれがここにあるのか?」
ネルソン

50
@Neil条件を否定するために、追加のCPU時間は必ずしも必要ではありません。x86にコンパイルされたCは、ジャンプ命令をJZ(ゼロの場合はジャンプ)if (foo)からJNZ(ゼロ以外の場合はジャンプ)にスワップできif (!foo)ます。
8bittree

71
明確な名前で追加のプロパティを作成する」:ドメインのより深い分析がない限り、これはローカルの問題(特定のビジネスルールの適用)を解決するためにグローバルスコープ(元のクラス)を変更する可能性があります。ここでできることの1つは、「var isSlave =!this.IsMaster」などの目的の状態でローカルブールを作成し、他のいくつかのプロパティを作成する代わりにローカルブールでifを適用することです。そのため、新しいプロパティを作成する前に、一粒一粒のアドバイスを取り、ドメインを分析するために時間をかけます。
マチャド

82
「3行のコード」ではなく、適切な対象者(少なくともプログラミングの基本的な知識を持っている人)のために書くことです。if、すでに条件が偽である可能性があるという事実について、明示的、またはあなたはそれをテストすることはないだろう。空のブロックは、それを期待する準備ができている読者がいないので、物事をより明確ではなく、より少なくします。そして、彼らはそれを止めて、どうやってそこに着くことができるかについて考えなければなりません。
ホッブズ

15
@Markは、コメントを付けたとしても、言うよりも明確ではif (!commonCase) { handle the uncommon case },ありません。
ポール

62

最初のルールに関して、これは無駄なタイピングの例です。入力に時間がかかるだけでなく、コードを読んでいる人に大きな混乱をもたらします。コードが不要な場合は、記述しないでください。これはelse、コードがifブロックから返されるときに、あなたのケースにデータが入力されないことにもなります:

if(condition) 
{
    doStuff();
    return whatever;
}

doSomethingElse(); // no else needed
return somethingelse;

2番目の点については、負の値を含むブール名を避けることをお勧めします。

bool doorNotOpen = false; // a double negative is hard to reason
bool doorClosed = false; // this is much clearer

ただし、指摘したように、これを再度ネガティブのテストを行わないように拡張すると、無駄な入力が増えます。以下は、空のifブロックを持つよりもはるかに明確です。

if(!condition)
{
    doStuff();
    return whatever;
}

120
だから...あなたは二重否定はノーだと言うことができますか?;)
Patsuan

6
@Patsuan、とても賢い。私はすきです。:)
デビッドアルノ

4
if-else with returnをどのように扱うべきかについて同意する人は多くないと感じ、また、すべてのシナリオで同じように扱うべきではないと言う人もいるかもしれません。私自身は強い好みはありませんが、他の多くの方法の背後にある議論を間違いなく見ることができます。
ダケリング

6
明らかに、if (!doorNotOpen)ひどいです。そのため、名前はできる限り積極的でなければなりません。if (! doorClosed)まったく問題ありません。
デビッドシュワルツ

1
ドアの例に関して、2つの例の名前は必ずしも同じではありません。物理的な世界doorNotOpenでは、doorClosed開いている状態と閉じている状態の間に遷移状態があるのと同じではありません。私の産業用アプリケーションでは、ブール状態が物理センサーによって決定されることが常にあります。ドアの開いている側にセンサーが1つしかない場合、ドアが開いているか開いていないとしか言​​えません。同様に、センサーが閉じた側にある場合は、閉じている、または閉じていないとしか言​​えません。また、センサー自体が論理状態の確認方法を決定します。
ピーターM

45

1.空のelseステートメントを支持する議論。

私はしばしば、その最初の構造に似たもの、空のその他のものを使用します(そしてそれを主張します)。コードの読者(人間と自動分析ツールの両方)に、プログラマーが状況に何らかの考えを入れたことを知らせます。else存在するはずだった欠落している記述は、人々を殺し、車両をクラッシュさせ、数百万ドルの費用がかかりました。たとえば、MISRA-Cは、最終的な行方不明者がif (condition_1) {do_this;} else if (condition_2) {do_that;} ... else if (condition_n) {do_something_else;}順番に意図的であるというコメントを少なくとも要求しています。他の高信頼性規格はさらに進んでいます。いくつかの例外を除き、elseステートメントの欠落は禁止されています。

1つの例外は、単純なコメントです/* Else not required */。これは、3行が空の場合と同じ意図を示します。その空のelseが不要な別の例外は、コードの読者と、他のelseを不要にする自動化された分析ツールの両方にとって明白であることです。例えば、if (condition) { do_stuff; return; }同様に、他の空の場合に必要とされていないthrow somethingか、goto some_label1の代わりにreturn

2.を優先if (condition)するための引数if (!condition)

これは人的要因のアイテムです。複雑なブール論理は多くの人をつまずかせます。熟練したプログラマーでさえも考えなければなりませんif (!(complex || (boolean && condition))) do_that; else do_this;。少なくとも、これをに書き換えif (complex || (boolean && condition)) do_this; else do_that;ます。

3.これは、空のthenステートメントを好むという意味ではありません。

2番目のセクションでは、「thou shalt」ではなく「prefer」と表示されます。これはルールではなくガイドラインです。このガイドラインが肯定的なif条件を好む理由は、コードが明確で明白であるべきだからです。空のthen句(例if (condition) ; else do_something;:)はこれに違反します。それは難読化されたプログラミングであり、最も熟練したプログラマーでさえも、if否定された形で条件をバックアップし、再読み取りします。そのため、そもそも否定形式で記述し、elseステートメントを省略します(または、そうすることが義務付けられている場合は、その効果に対する空のelseまたはコメントを付けます)。



1で終わるthen節returnthrowまたはgoto空のelseを必要としないthen節を書きました。else節が不要であることは明らかです。しかし、どうgotoですか?余談ですが、安全重視のプログラミングルールでは、早期復帰が許可されない場合があり、ほとんどの場合、例外のスローは許可されません。ただしgoto、制限された形式(例:)で許可されgoto cleanup1;ます。この制限された使用gotoは、一部の場所で推奨される方法です。たとえば、Linuxカーネルには、こうしたgotoステートメントがぎっしり詰まっています。


6
!簡単に見落とされます。簡潔すぎます。
するThorbjörnRavnアンデルセン

4
いいえ、空のelseは、プログラマーが何らかの考えを入れたことを明確にしません。「いくつかのステートメントが計画されていて、それらが忘れていたのか、なぜ空の句があるのか​​」という混乱を招きます。コメントははるかに明確です。
サイモン

9
@Simon:典型的な形式はelse { /* Intentionally empty */ }、またはそれらの線に沿ったものです。空のelseは、ルール違反を無意識に検索する静的アナライザーを満たします。コメントは、空のelseが意図的なものであることを読者に知らせます。繰り返しになりますが、経験豊富なプログラマーは通常、コメントを不必要なものとして省略しますが、空のその他のものは省略しません。高信頼性プログラミングはそれ自体の領域です。構造は部外者にはかなり奇妙に見えます。これらの構造は、ハードノック、生と死、$$$$$$$$$が手近にあるときに非常に難しいノックの教訓から使用されます。
デビッドハンメン

2
空のelse節がそうでない場合、空のthen節が悪いことであることがわかりません(そのスタイルを選択すると仮定します)。私は見ることができますif (target == source) then /* we need to do nothing */ else updateTarget(source)
ベルギ

2
@ThorbjørnRavnAndersennope notは、他のビット演算子や論理演算子と同様に、C ++のキーワードです。代替演算子表現を参照してください。
ルスラン

31

私は非常にまれなケースで空のelse-branch(時には空のif-branch)を使用します:ifとelseの両方の部分を何らかの方法で処理する必要があることが明らかであるが、いくつかの非自明な理由でケースを処理できる場合何もしない。したがって、elseアクションが必要なコードを読んでいる人は、何かが足りないとすぐに疑い、時間を無駄にします。

if (condition) {
    // No action needed because ...
} else {
    do_else_action()
}

if (condition) {
    do_if_action()
} else {
    // No action needed because ...
}

だがしかし:

if (condition) {
    do_if_action()
} else {
    // I was told that an if always should have an else ...
}

5
この。私は、文if test succeeds -> no action needed -> else -> action neededが意味的に文と非常に異なっていると思いますif it applies that the opposite of a test outcome is true then an action is needed。私はマーティン・ファウラーの引用を思い出します:「誰でもコンピューターが理解できるコードを書くことができます;優れたプログラマーは人間が理解できるコードを書くことができます」。
タソスパパスティリアーノウ

2
@TasosPapastylianouそれは不正行為です。「テストが成功した場合->アクションが不要」の反対は、「テストが成功しなかった場合->アクションが必要」です。約10語で埋めました。
ジェリーB

@JerryBそれは「テスト」に依存します。否定は(言語学的に)簡単な場合もありますが、そうでない場合もあり、混乱を招きます。そのような場合、「結果が真であるの否定/反対」対「結果が真ではない」について話す方が明確です。しかし、ポイントは、「空の」ステップを導入するか、変数名の意味を逆にすることがさらに明確になるということです。これは、「de morgan」の状況で典型的です。たとえば、if ((missing || corrupt) && !backup) -> skip -> else do stuffより明確です(+異なる暗黙の意図)if ((!missing && !corrupt) || backup) -> do stuff
Tasos Papastylianou

1
@TasosPapastylianouあなたが書くif(!((missing || corrupt) && !backup)) -> do stuffか、より良いことができますif((aviable && valid) || backup) -> do stuff。(ただし、実際の例では、使用する前にバックアップが有効かどうかを確認する必要があります)
-12431234123412341234123

2
@TasosPapastylianou私が言ったことに二重否定はありますか?もちろん、変数名として破損していないものを使用している場合、明確なポイントがあります。ただし、このような混合ブール演算子を使用する場合、一時変数を使用して、:で使用する方が良いかもしれませんが、個人的にはそれがさらに明確になると感じています。iffile_ok = !missing && !corrupt; if(file_ok || backup) do_stuff();
ボールドリック

23

他のすべてが等しい場合、簡潔さを好みます。

あなたが書いていないものは、誰も読んで理解する必要はありません。

明示的であることは有用ですが、あなたが書いたものが本当にあなたが書きたかったものであることが過度の冗長性なしに明らかになった場合のみです。


したがって、空のブランチは避けてください。それらは役に立たないだけでなく、珍しいため混乱を招きます。

また、if-branchから直接終了する場合は、else-branchを記述しないでください。

明示性の有用なアプリケーションは、switch-casesを通過するたびにコメントを入れ// FALLTHRU、空のstatementが必要な場所にコメントまたは空のブロックを使用することですfor(a;b;c) /**/;


7
// FALLTHRUうーん、SCREAMING CAPSではなく、txtspkの略語ではありません。そうでなければ、私は同意し、この慣行を自分で行います。
コーディグレー

7
@CodyGray-これは、叫ぶのが良いアイデアの1つです。ほとんどのswitchステートメントは、各ケースをで終了しbreakます。それを怠るとbreak、いくつかの壮大なソフトウェア障害が発生します。フォールスルーが意図的であるとコードの読者に叫ぶコメントは良いことです。静的分析ツールはこの特定のパターンを検索でき、フォールスルー状態について文句を言う必要はなく、さらに良いものになります。
デビッドハンメン

1
@Wossname:をチェックしたところ、のvimバリエーションを認識しませんFALLTHRU。そして、私は、十分な理由があると思います:TODOそして、FIXMEコメントはgit grep、コードにある既知の欠陥とそれらがどこにあるかを尋ねたいので、grepableである必要があるコメントです。フォールスルーは欠陥ではなく、それをgrepする理由はありません。
cmaster

4
@DavidHammenいいえ、叫ぶことは良い考えではありません。予想されるブレークの代わりに//フォールスルーがある場合、開発者はすぐに理解するのに十分なはずです。また、// fallthroughは欠陥について話すのではなく、単に状況が考慮されたこと、および中断を知らせるだけです。欠落しているように見えますが、実際には存在しないことが意図されています。これは純粋に情報提供の目的であり、何も叫ぶことはありません。
cmaster

1
@cmaster-叫ぶのは得策ではないというのがあなたの意見です。他の人の意見は異なります。そして、ちょうどので、あなたの認識しないのvimの設定は、FALLTHRU他の人がそうするのvimを設定していないことを意味するものではありません。
デビッドハンメン

6

私の知る限りではありませんが、IFステートメントの肯定的または否定的な条件に関する厳格な規則はありません。個人的には、該当する場合、ネガティブではなくポジティブなケースのコーディングを好みます。ただし、空のIFブロックを作成し、その後にロジックがいっぱいのELSEを作成するようになった場合、これを行うことはほとんどありません。このような状況が発生した場合、とにかくポジティブケースのテストにリファクタリングするのに3秒ほどかかります。

あなたの例について私が本当に気に入らないのは、空白のELSEが占める完全に不要な垂直スペースです。これを行う理由はまったくありません。ロジックに何も追加せず、コードの実行内容を文書化するのに役立ちません。また、読みやすさもまったく向上しません。実際、追加された垂直方向のスペースが読みやすさを低下させる可能性があると主張します。


2
この不必要な垂直方向のスペースは、常に中括弧を使用すること、行方不明を許可しないこと、およびインデントにAllmanスタイルを使用することの義務の結果です。
デビッドハンメン

まあ、常に中括弧を使用するのは良いことだと思うでしょう。なぜなら、それは開発者の意図を明示的にするからです-コードを読むときに当て推量の余地はありません。それは馬鹿げているように聞こえるかもしれませんが、特にジュニア開発者を指導する場合は、中括弧の欠落に関連する間違いが発生します。個人的には、あなたが言及したまさにその理由で、不必要な垂直方向のスペースのために、オールマンスタイルのインデントのファンではありませんでした。しかし、それは私の意見であり、個人的なスタイルです。それは私が最初に学んだことだけなので、常に読みやすいと感じています。
ランジュクルー

パーソナルスタイル:使用するブレーススタイル(Allman、1TBなど)に関係なく、常にブレースを使用します。
デビッドハンメン

複雑な条件や理解が難しいと思われる条件は、ほとんどの場合、独自のメソッド/関数にリファクタリングすることで解決できます。このようなものif(hasWriteAccess(user,file))は下で複雑になる可能性がありますが、一目で結果がどうあるべきかを正確に知っています。たとえばif(user.hasPermission() && !file.isLocked())、適切な名前のメソッド呼び出しがいくつかの条件にすぎない場合でも、ポイントが得られるため、ネガティブな問題は少なくなります。
クリスシュナイダー

同意した。それから再び、私は可能な限りリファクタリングの大ファンです:)
ランジュクルー

5

明示的なelseブロック

私はこれをすべてのif声明を網羅する包括的な声明としては同意しelseませんが、習慣からブロックを追加することが良いことです。

if声明は、私の心に、実際には二つの異なる機能をカバーしています。

私たちが何かをすることになっているなら、ここでそれをしてください。

このようなものは明らかに部品を必要としませelse

    if (customer.hasCataracts()) {
        appointmentSuggestions.add(new CataractAppointment(customer));
    }
    if (customer.isDiabetic()) {
        customer.assignNurse(DiabeticNurses.pickBestFor(customer));
    }

場合によってelseは、誤解を招く可能性があると主張することもあります。

    if (k > n) {
        return BigInteger.ZERO;
    }
    if (k <= 0 || k == n) {
        return BigInteger.ONE;
    }

はないと同じ

    if (k > n) {
        return BigInteger.ZERO;
    } else {
        if (k <= 0 || k == n) {
            return BigInteger.ONE;
        }
    }

機能的には同じですが。最初ifに空の文字を書くと、else不必要にresultい2番目の結果になる可能性があります。

特定の状態を確認している場合は、そのelse偶然性をカバーすることを思い出させるために空を追加することをお勧めします

        // Count wins/losses.
        if (doors[firstChoice] == Prize.Car) {
            // We would have won without switching!
            winWhenNotSwitched += 1;
        } else {
            // We win if we switched to the car!
            if (doors[secondChoice] == Prize.Car) {
                // We picked right!
                winWhenSwitched += 1;
            } else {
                // Bad choice.
                lost += 1;
            }
        }

これらのルールは、新しいコードを作成する場合にのみ適用されることに注意してください。IMHO空のelse句はチェックイン前に削除する必要があります。


テスト用trueではないため、false

繰り返しますが、これは一般的なレベルでは良いアドバイスですが、多くの場合、これによりコードが不必要に複雑になり、読みにくくなります。

のようなコードにもかかわらず

    if(!customer.canBuyAlcohol()) {
        // ...
    }

読者に不快感を与えるが、それを作る

    if(customer.canBuyAlcohol()) {
        // Do nothing.
    } else {
        // ...
    }

悪くないにしても、少なくとも同じくらい悪いです。

私は何年も前にBCPLでコーディングし、その言語でありIFUNLESSあなたがはるかに読み出し可能としてコーディングできるよう句:

    unless(customer.canBuyAlcohol()) {
        // ...
    }

大幅に改善されていますが、まだ完全ではありません。


私の個人的なプロセス

一般に、新しいコードを作成するときは、その不測の事態をまだカバーしていないことを思い出させるためelseに、ifステートメントに空のブロックを追加することがよくあります。これにより、DFSトラップを回避し、コードを確認するときに、やるべきことがあることに気付くことができます。ただし、通常はTODO追跡するためにコメントを追加します。

  if (returnVal == JFileChooser.APPROVE_OPTION) {
    handleFileChosen();
  } else {
    // TODO: Handle case where they pressed Cancel.
  }

elseコードの臭いをしばしば示すことがあるので、一般的にコードではほとんど使用しません。


thngsを実装するときに「空」のブロックのあなたの取扱いは...標準のスタブアウトコードのように読み込む
デュプリケータ

unlessブロックは良い提案で、ほとんどBCPLに限りません。
-tchrist

@TobySpeightおっと。私が書いたもの...が実際にあったことがどういうわけか私の注意を逃しましたreturn。(実際にはk=-1n=-2で、最初のリターンが取られますが、これは大部分が
意味

現代のPerlにはとがifありunlessます。さらに、ステートメントの後にこれらを許可するため、print "Hello world!" if $born;またはprint "Hello world!" unless $dead;と言うことができ、両方があなたが思っていることを正確に行います。
CVn

1

最初の点では、IFステートメントをこのように強制的に使用する言語(Opalでは、メインフレームシステムにGUIフロントエンドを配置するためのメインフレームスクリーンスクレーパーの背後にある言語)を使用しました。そしてELSE。楽しい経験ではありませんでした!

コンパイラーは、このような追加のELSE節を最適化することを期待しています。しかし、ライブコードの場合、何も追加されません(開発中、追加のコードの有用なマーカーになる可能性があります)。

これらの余分な句のようなものを使用するのは、CASE / WHEN型処理を使用するときです。空であっても、常にデフォルト句を追加します。これは、そのような節が使用されない場合にエラーが発生する言語の長期的な習慣であり、物事が本当にただ抜け落ちるべきかどうかについての考えを強制します。

メインフレーム(PL / 1やCOBOLなど)の慣習では、ネガティブチェックの効率が低いことが受け入れられていました。これは2番目のポイントを説明できますが、最近では非常に重要な効率の節約がありますが、これはミクロ最適化として無視されます。

負論理は読みにくい傾向がありますが、そのような単純なIFステートメントではそれほどではありません。


2
なるほど、ある時点でそれ一般的な慣行でした。
パツアン

@Patsuan-はい、ある程度。ただし、メインフレームアセンブラは、パフォーマンスが重要なコードの重大な代替手段でした。
キックスタート

1
「ずっと前に...ネガティブチェックはあまり効率的ではなかったことが受け入れられました。」まあ、彼らはしているコンパイラが最適化しない限りif !A then B; else Cif A then C; else B。条件の否定の計算は、余分なCPU命令です。(あなたが言うように、これは大幅に効率が低下する可能性は低いです。)
デイビッドリチャービー

@DavidRicherbyそして、一般的に言えば、いくつかの言語はそのような最適化を本当に難しくすることができます。たとえば、オーバーロードさ!れた==演算子とC ++を使用します。誰もがすべきではないことを実際に行うこと、あなたの心...
からCVn

1

空のelseブロックは実質的に常に電子インクの有害な浪費であるというほとんどの答えのスタンドを次にします。特別な理由がない限り、これらを追加しないでください。その場合、空のブロックは空にならないはずです。その理由を説明するコメントを含める必要があります。

ただし、ネガティブを回避することに関する問題には、さらに注意を払う必要があります。通常、ブール値を使用する必要がある場合は常に、設定時に動作するコードのブロックと、設定されていないときに動作する他のブロックが必要です。そのため、否定のルールを適用する場合は、if() {} else {...}ステートメント(空のifブロック!)を使用するか、否定値を含むブール値ごとに2番目のブール値を作成します。どちらのオプションも、読者を混乱させるため、良くありません。

有用なポリシーは次のとおりです。ブール値の名前内で否定形式を使用せず、否定を単一として表現し!ます。のような声明if(!doorLocked)は完全に明確であり、if(!doorUnlocked)結び目のような声明です。後者のタイプの式は!if()条件に単一の式が存在することではなく、避ける必要があるものです。


0

間違いなく悪い習慣だと思います。elseステートメントを追加すると、何もしないコードが無意味な行になり、読みにくくなります。


1
私は...あなたは成績パフォーマンス期間ごとに生産さ海上交通路に基づく雇用者のために働いたことはない聞く
からCVn

0

空のifブロックを持つ2番目のケースの処理については、まだ言及されていない別のパターンがあります。これに対処する1つの方法は、ifブロックに戻ることです。このような:

void foo()
{
    if (condition) return;

    doStuff();
    ...
}

これは、エラー状態をチェックするための一般的なパターンです。肯定的なケースがまだ使用されており、その内部はもはや空ではなく、将来のプログラマーは、ノーオペレーションが意図的であったかどうか疑問に思うようになります。また、新しい関数を作成する必要がある場合があるため、読みやすさも向上します(したがって、大きな関数を小さな個々の関数に分割します)。


0

「常にelse節を持っている」という議論を考えるとき、他の答えでは見なかった1つのポイントがあります。それは、関数型プログラミングスタイルで意味をなします。並べ替え。

関数型プログラミングスタイルでは、ステートメントではなく式を扱います。したがって、すべてのコードブロックには、if-then-else式を含む戻り値があります。ただし、空のelseブロックは除外されます。あなたの例を挙げましょう:

var even = if (n % 2 == 0) {
  return "even";
} else {
  return "odd";
}

現在、CスタイルまたはCスタイルにインスパイアされた構文(Java、C#、JavaScriptなど)の言語では、これは奇妙に見えます。ただし、次のように記述した場合、より親しみやすくなります。

var even = (n % 2 == 0) ? "even" : "odd";

去るelse値を引き起こすここで、空のブランチは、未定義する-ほとんどの場合、我々は機能をプログラミングする際に有効な場合になりたいではないものを。完全に除外する場合も同じです。ただし、繰り返しプログラミングする場合、常にelseブロックする理由はほとんどありません。


0

... ifステートメントの後にelseステートメントを続ける必要があります(何かを挿入するかどうか)。

私は反対するif (a) { } else { b(); }として再記述する必要がありますif (!a) { b(); }if (a) { b(); } else { }として再記述する必要がありますif (a) { b(); }

ただし、空のブランチはめったにありません。これは、通常は空のブランチに行ったことをログに記録するためです。この方法で、純粋にログメッセージから開発できます。デバッガーを使用することはほとんどありません。実稼働環境では、デバッガーを取得しません。開発に使用するのと同じツールを使用して、生産上の問題をトラブルシューティングできると便利です。

第二に、偽ではなく真の値をテストする方が良いです。つまり、「!doorOpened」変数の代わりに「doorClosed」変数をテストする方がよいということです。

私はこれについて複雑な気持ちを持っています。持っdoorCloseddoorOpenedいることの不利な点は、注意する必要のある単語/用語の数が倍になる可能性があることです。もう一つの欠点は、時間をかけての意味であるdoorCloseddoorOpened変更される可能性があり(他の開発者があなたの後に入ってくる)、あなたは、もはや互いの正確否定している二つの特性で終わるかもしれません。否定を避ける代わりに、ビジネスユーザーのボキャブラリと与えられた要件に合わせて、コードの言語(クラス名、変数名など)を適合させることを重視しています。を避けるために、まったく新しい用語を作りたくありません。!その用語が、ビジネスユーザーが理解できない開発者にとってのみ意味を持つ場合。開発者に、ユーザーおよび要件を作成する人々と同じ言語を話してもらいたい。新しい用語がモデルを単純化する場合、それは重要ですが、それは要件ではなく、最終的に処理されるべきであり、後ではありません。開発者は、コーディングを開始する前にこの問題を処理する必要があります。

私は本能を疑う傾向があります。

自分自身に疑問を持ち続けるのは良いことです。

それは良い/悪い/「問題ではない」プラクティスですか?

ある程度、これの多くは重要ではありません。コードをレビューして、チームに適応させます。それは通常正しいことです。チームの全員が特定の方法でコーディングしたい場合は、おそらくそのようにすることをお勧めします(1人を変更する-自分自身-人々のグループを変更するよりもストーリーポイントが少なくなります)。

それは一般的な習慣ですか?

空の枝を見たことを覚えていない。ただし、否定を避けるためにプロパティを追加する人がいます。


0

質問の2番目の部分のみを取り上げます。これは、現実の世界で産業システムで作業し、デバイスを操作するという私の観点から来ています。

ただし、これは何らかの形で回答ではなく拡張コメントです。

記載されている場合

第二に、偽ではなく真の値をテストする方が良いです。つまり、「!doorOpened」変数の代わりに「doorClosed」変数をテストする方がよいということです。

彼の議論は、コードが何をしているのかを明確にするということです。

私の観点からは、実際には少なくとも3状態であるにもかかわらず、ドアの状態は2状態であると仮定しています。

  1. ドアが開いています。
  2. ドアは完全に開いているわけでも完全に閉じているわけでもありません。
  3. ドアが閉じています。

したがって、単一のバイナリデジタルセンサーの場所に応じて、次の2つの概念のいずれかしか推測できません。

  1. センサーがドアの開いた側にある場合:ドアが開いているか開いていない
  2. センサーがドアの閉じた側にある場合:ドアが閉じているか閉じていないかのいずれかです。

また、バイナリ否定を使用してこれらの概念を交換することはできません。したがってdoorClosed!doorOpened同義語ではない可能性が高く、同義語のふりをしようとする試みは、実際に存在するよりもシステム状態の知識が大きいと仮定する誤った考えです。

あなたの質問に戻って、変数が表す情報の起源に一致する冗長性をサポートします。したがって、情報がドアの閉じた側から派生しているdoorClosed場合などに進みます。これは、必要に応じてさまざまなステートメントでいずれかdoorClosedまたは!doorClosed必要に応じて使用することを意味し、否定の使用と混乱する可能性があります。ただし、システムの状態に関する仮定を暗黙的に伝播することはしません。


私が行う作業の議論のために、システムの状態について入手できる情報の量は、システム全体に必要な機能に依存します。

時々、ドアが閉じているか閉じていないかだけを知る必要があります。この場合、単一のバイナリセンサーで十分です。しかし、他の時には、ドアが開いている、閉じている、または移行中であることを知る必要があります。このような場合、2つのバイナリセンサー(ドアの動きの各極端-ドアの開閉を同時にチェックするエラー)が存在するか、ドアがどの程度開いたかを測定するアナログセンサーが存在します。

最初の例は、電子レンジのドアです。ドアが閉じているか閉じていないかに基づいて、オーブンの操作を有効にします。ドアがどれだけ開いているかは気にしません。

2番目の例は、単純なモーター駆動のアクチュエーターです。アクチュエータが完全に出ているときは、モーターを前方に駆動することを禁止します。そして、アクチュエーターが完全にインになったときにモーターを逆方向に駆動することを禁止します。

基本的に、センサーの数とタイプは、必要な機能を実現するために必要なものの要件分析に対してセンサーのコスト分析を実行することになります。


「私の視点から、仮定は、実際には、少なくとも三元の状態のとき、ドアの状態がバイナリ状態であることをここで行われている:」「あなたは、オーブンの操作がドアに基づいて閉じるか閉じていないされている可能ドアがどれだけ開いているかは気にしません。」互いに矛盾します。また、質問はドアやセンサ​​ーに関するものではないと思います。
-Sanchises

@Sanchisesあなたがそれらを文脈から外したので、ステートメントは矛盾していません。最初のステートメントは、3つの状態の2つの相反する2進測定値を2項否定を介して交換することはできないというコンテキストです。2番目のステートメントは、アプリケーションが正しく機能するためには、3状態の部分的な知識だけで十分であるというコンテキストにあります。ドアに関しては、OPの質問はドアが開いているか閉じているかについて言及しました。データの処理方法に影響を与える可能性がある明白な仮定を指摘しています。
ピーターM

-1

具体的なスタイルのルールは常に悪いです。ガイドラインは優れていますが、最終的には、ガイドラインに従わない何かをすることで、より明確にすることができる場合がしばしばあります。

とはいえ、空のelse「行を無駄にする」「余分なタイピング」には多くの憎しみがありますが、それは単に悪いことです。垂直方向のスペースが本当に必要な場合は、ブラケットを同じ行に移動するという引数を作成できますが、それが問題である場合は、とにかく{を別の行に置くべきではありません。

他の場所で述べたように、elseブロックを使用すると、他のケースでは何も実行しないことを明示的に示すのに非常に役立ちます。多くの関数型プログラミング(他の必要な場合)を行った後、@ OldCurmudgeonが述べているように、実際には2つの異なるユースケースがありますが、ifを書くときは常にelseを考慮する必要があることを学びました。他の人がいるべきであり、そうでないべきです。悲しいことに、リンターと一緒に言うまでもなく、常に一目でわかるものではないため、独断的な「常にelseブロックを置く」。

「ネガティブなし」に関しては、やはり絶対的なルールは悪いです。空のifを持つことは奇妙です。特にifがelseを必要としないifタイプの場合、!または== falseが悪いです。そうは言っても、ネガティブが理にかなっているケースはたくさんあります。一般的な例は、値のキャッシュです。

static var cached = null

func getCached() {
    if !cached {
        cached = (some calculation, etc)
    }

    return cached
}

実際の(メンタル/英語)ロジックに負の値が含まれる場合、ifステートメントも含まれます。

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