0

多くのエラーチェックを伴うメソッドの書き方について、別のプログラマーと意見の相違がありました。

public void performAction() {
  if (test1) {
    if (test2) {
      if (test3) {
        // DO STUFF
      } else {
        return "error 3";
      }
    } else {
      return "error 2";
    }
  } else {
    return "error 1";
  }
}

-

public void performAction() {     
  if (!test1) {
    return "error 1";
  }
  if (!test2) {
    return "error 1";
  }
  if (!test3) {
    return "error 1";
  }
  // DO STUFF
}

私には、ifステートメントのネストが深いため、最初の例が読みにくくなっています。
2 番目のものは、3 つのreturnがあるにもかかわらず、より読みやすくなっています。

コードコンプリートがそれについて何を言っているのか好奇心でチェックしましたが、これを処理する方法についてあまり確信が持てませんでした:

ネストの一番下にあるエラー状態のスタックは、適切に記述されたエラー処理コードの兆候です。

しかしその後

ルーチンの本体を 4 つの if ステートメント内でインデントすることは、特に最も内側の if ステートメント内に多くのコードがある場合、見栄えが悪くなります。

2番目の例のように、ガード句の使用を検討してください

各ルーチンでのリターンの数を最小限に抑えます。ルーチンを理解するのは、一番下を読んでいて、それが上のどこかで返された可能性に気付いていない場合、理解するのが難しくなります。

メソッドのエラー チェック部分をどのように記述して、読みやすくエラーを起こしやすくしますか?

4

3 に答える 3

0

例外処理と自動化されたリソース管理を備えた言語を使用している場合、同僚はおそらく、外部入力エラーが発生した場合に早期終了するという好みのスタイルに慣れるはずです。

関数の出口をスコープの一番下にシフトしようとするアイデアは、例外処理や自動化されたリソース管理 (例: デストラクタのない言語や C のような GC) が登場する以前の時代には有用でした。これは、エラーの回復には手動によるクリーンアップが必要になることが多かったためです。

これらの手動クリーンアップのケースでは、関数が必要とする一時的なリソースを作成するロジックの関数の上部と、関数の下部に向かって見ることができるように、出口を関数の下部に移動すると便利なことがよくありました。これらのリソースの対称的なクリーンアップを確認してください。

アセンブリなどの場合jumps/branches、クリーンアップが発生する関数の下部にエラー ラベルが表示されることがよくあります。gotosこの目的で使用するCでも珍しくありません。

また、前述のように、深いネスティングは多くの精神的なオーバーヘッドをもたらします。あなたの脳は、自分がどこにいるかを記憶しようとする、深くネストされたスタックのように機能しなければなりません。頑固な C コーダーである Linus Torvalds でさえ、次のように言うのが好きです。あなたのコードはすでに壊れており、リファクタリングする必要があります (正確な数について彼に同意するかどうかはわかりませんが、ロジックを難読化する方法に関しては彼の意見があります)。

C++ のような最新の言語に移行すると、デストラクタを介してリソース管理が自動化されます。リソースは、リソース取得と呼ばれるものに準拠することによって自動的にクリーンアップを処理する必要があるため、関数はクリーンアップの詳細について言及しなくなります(正確には最適な名前ではありません)。これにより、エラー処理ロジックを最下部に配置しようとするスタイルを支持する大きな理由の 1 つがなくなります。

その上、C++ のような言語を使用すると、あらゆる場所で例外がスローされる可能性があります。そのため、コードの 1 行おきに、次のようなロジックで非表示の暗黙的な終了を行う効果があることは珍しくありません。

if an exception occurs:
    automatically cleanup resources and propagate the error

そのため、隠れた時期尚早の出口がいたるところにあります。したがって、そのような言語を使用すると、例外が発生した場合の早期終了に慣れる必要があるだけでなく、強制的に終了することになり、他に選択肢がなくなります。これらの言語の可読性/トレーサビリティに関する限り、次のように単純化することはできません。

if something bad happened:
     return error

私が提案するルールの 1 つの例外は、静的分岐予測です。最小のマイクロ効率が可読性よりも重要な、非常にパフォーマンスが重要なコードを作成している場合は、Intel がアドバイスするように、一般的なケースの実行ラインを優先するようにブランチを重み付けする必要があります。したがって、代わりに:

if something exceptional happened:
    return error

...パフォーマンスのために、ロジックを逆にして、代わりにこれを行うことができます:

if something normal happened:
     ...
     return success
return error
于 2015-05-25T09:06:34.077 に答える
0

これは私の意見。

「各ルーチンの返品数を最小限に抑える」という古いマントラは、少し時代遅れのようです。多くの操作が実行される 8 ~ 10 行の長いコードのメソッドがある場合に非常に適しています。

単一の責任と非常に短い方法を強調する新しい考え方は、それを少し不必要にしているように見える. メソッド全体が直接操作を行うのではなく、単純にエラー処理を処理する場合は、クリーンな形式で複数のリターンを返すのが最適です。

どちらの場合でも、if をネストすると、読み取り可能性が大幅に低下します。

私が行う最適化の 1 つは、論理フローを明確に示すために、if-else-if 構造を使用することです。

サンプルコード:

public void Execute() 
{     
    if (test1)
    {
        return;
    }
    else if (test2)
    {
        return;
    }
    PerformAction();
}

private void PerformAction()
{
    //DO STUFF
}
于 2014-10-08T19:42:50.353 に答える