警告!確かに別の言語に関する質問に答えようとして、例外処理がどのように行われるべきかについて、おそらく異なる考えでここに来るC ++プログラマー!
この考えを考えると:
たとえば、HTTPリクエストを実行し、取得したデータを返すフェッチリソースがあるとします。また、ServiceTemporaryUnavailableやRateLimitExceededのようなエラーの代わりに、RetryableErrorを発生させ、要求を再試行するだけで特定の失敗を気にしないことをコンシューマに提案します。
...私がお勧めすることの1つは、エラーを報告することと、コードの一般性を低下させたり、例外のために多くの「翻訳ポイント」を必要とする方法でそれに対応するアクションコースを混在させることです。
たとえば、ファイルの読み込みを伴うトランザクションをモデル化すると、いくつかの理由で失敗する可能性があります。おそらく、ファイルの読み込みには、ユーザーのマシンに存在しないプラグインの読み込みが含まれます。おそらくファイルは単に破損しており、解析中にエラーが発生しました。
何が起こっても、ユーザーに何が起こったのかを報告し、ユーザーがそれに対して何をしたいのかを促します(「再試行、別のファイルをロード、キャンセル」)。
投げる人対キャッチャー
この場合に発生したエラーの種類に関係なく、その一連のアクションが適用されます。解析エラーの一般的な考え方には埋め込まれていません。プラグインの読み込みに失敗するという一般的な考え方には埋め込まれていません。ファイルをロードする正確なコンテキスト(ファイルのロードと失敗の組み合わせ)でこのようなエラーが発生するという考えに組み込まれています。だから通常、私は大雑把に言っcatcher's
て、スローされた例外(例:ユーザーにオプションを要求する)に応じてアクションのコースを決定する責任ではなく、を参照しますthrower's
。
別の言い方をthrow
すれば、特にスローする機能が一般的に適用可能な場合、例外が通常この種のコンテキスト情報を欠いているサイトです。彼らがこの情報を持っている完全に一般化された状況でさえ、あなたはthrow
サイトにそれを埋め込むことによって回復行動に関して自分自身を追い詰めることになります。catch
通常、アクションのコースを決定するために利用可能な情報量が最も多いサイトであり、特定のトランザクションに対してアクションのコースが変更される場合に変更する中心的な場所を提供します。
例外をスローしようとすると、何が問題なのかを報告せず、何をすべきかを判断しようとすると、コードの汎用性と柔軟性が低下する可能性があります。解析エラーが常にこの種のプロンプトにつながるとは限りません。例外がスローされるコンテキスト(スローされたトランザクション)によって異なります。
盲目の投げ手
ちょうど一般的に、例外処理の設計の多くは、多くの場合、盲目の投げ手のアイデアを中心に展開します。例外がどのようにキャッチされるのか、どこで行われるのかはわかりません。同じことが、手動のエラー伝播を使用した古い形式のエラー回復にも当てはまります。エラーが発生したサイトにはユーザーのアクションコースは含まれず、発生したエラーの種類を報告するための最小限の情報のみが埋め込まれます。
反転した責任とキャッチャーの一般化
これについてもっと慎重に考えると、これが誘惑になるようなコードベースを想像しようとしていました。私の想像(おそらく間違っている)は、あなたのチームがまだここで「消費者」の役割を果たしており、呼び出しコードの大部分も実装しているということです。おそらくtry
、同じ一連のエラーに遭遇する可能性のある多くの異なるトランザクション(多くのブロック)があり、すべてが設計の観点から、回復アクションの均一なコースにつながるはずです。
Lightness Races in Orbit's
細かい答え(賢明なライブラリ指向の考え方から来ていると思います)からの賢明なアドバイスを考慮すると、トランザクション回復サイトの近くでのみ、「何をすべきか」例外をスローするように誘惑されるかもしれません。
ここから、実際に「何をすべきか」の懸念を集中化するが、それでもキャッチのコンテキスト内にある、中間の共通トランザクション処理サイトを見つけることが可能かもしれません。
これは、これらのすべての外部トランザクションが使用する何らかの一般的な関数を設計できる場合にのみ適用されます(例:呼び出す別の関数を入力する関数、または洗練されたキャッチを行うこの中間トランザクションサイトをモデル化するオーバーライド可能な動作を持つ抽象トランザクションベースクラス)。
ただし、さまざまなエラーに対応して、ユーザーのアクションコースを一元化する責任があります。これは、スローではなくキャッチのコンテキスト内です。単純な例(Python風の擬似コード。私は経験豊富なPython開発者ではありませんので、これについてもっと慣用的な方法があるかもしれません):
def general_catcher(task):
try:
task()
except SomeError1:
# do some uniformly-designed recovery stuff here
except SomeError2:
# do some other uniformly-designed recovery stuff here
...
[願わくはgeneral_catcher
] よりも良い名前を付けてください。この例では、実行するタスクを含む関数を渡すことができますが、関心のあるすべての種類の例外に対して一般化/統一されたキャッチ動作の恩恵を受け、引き続き「何をする」部分を拡張または変更しますあなたはこの中心的な場所から好きであり、それでもcatch
これが通常奨励されているコンテキスト内にあります。何よりも、私たちはスローサイトが「何をすべきか」(「ブラインドスロー」の概念を維持する)を自分自身に関係させないようにすることができます。
ここでこれらの提案のどれも役に立たず、とにかく「するべきこと」の例外をスローする強い誘惑がある場合、主にこれは非常に反イディオマティックであり、一般化された考え方を落胆させる可能性があることに注意してください。