web-dev-qa-db-ja.com

失敗とレイズインRuby:スタイルガイドを本当に信じるべきか?

Rubyは、プログラムで例外を発生させる2つの可能性を提供します。raisefailです。どちらもKernelメソッドです。文書によると、それらは完全に同等です。

習慣から、これまでraiseのみを使用しました。今、私はいくつかの推奨事項を見つけました(たとえば here )、例外をキャッチするためにraiseを使用し、処理することを意図していない重大なエラーに対してfailを使用します。

しかし、それは本当に理にかなっていますか?クラスまたはモジュールを作成しているときに、failで通知する問題を引き起こすと、コードをレビューしているプログラミングの同僚はあなたの意図を喜んで理解するかもしれませんが、usingほとんどの場合、私のコードは私のコードを見ず、例外がraiseによって引き起こされたかfailによって引き起こされたかを知る方法がありません。したがって、raiseまたはfailの慎重な使用は、彼女がそれを処理すべきかどうかにかかわらず、彼の決定に影響を与えることはできません。

誰かが私の議論の欠陥を見ることはできますか?または、failの代わりにraiseを使用する可能性のある他の基準がありますか?

34
user1934428

例外をキャッチするには「raise」を使用し、処理することを意図していない重大なエラーには「fail」を使用します

これは、 公式スタイルガイド やあなたが提供したリンクが問題について言っていることではありません。

ここでの意味は、raiseブロックでのみrescueを使用することです。別名failingと言いたいときにfailを使用し、rethrowingraiseを使用する例外。

"does it matter"部分については、最も筋金入りの厳密に従うルールの1つではありませんが、どの規約にも同じ議論をすることができます。次の順序に従う必要があります。

  1. プロジェクトスタイルガイド
  2. あなたの会社スタイルガイド
  3. コミュニティスタイルガイド

理想的には、3つは同じでなければなりません。


UpdateこのPR (2015年12月)の時点で、規則は常にraiseを使用することです。

44
ndnenkov

私はかつて Jim Weirich とこの会話について話し合いました。それ以来、何らかの理由で私のメソッドが明示的に失敗し、failが再失敗するときは常にraiseを使用しました。スローされた例外。

以下は、ジムからのメッセージを含む投稿です(彼が直接私に言ったことはほぼ逐語的です): http://www.virtuouscode.com/2014/05/21/jim-weirich-on-exceptions/

投稿の関連テキストは、ジムに帰属する引用です。

例外に関する私の基本的な哲学(およびその他のランダムな考え)は次のとおりです。

メソッドを呼び出すとき、メソッドが何を達成するかについて特定の期待があります。正式には、これらの期待は事後条件と呼ばれます。メソッドは、事後条件を満たさない場合は常に例外をスローする必要があります。

この戦略を効果的に使用するには、Design by Contractおよび事前条件と事後条件の意味を少し理解する必要があることを意味します。とにかく知っておくのは良いことだと思います。

以下に具体的な例を示します。 Rails model saveメソッド:

model.save!
-- post-condition: The model object is saved.

何らかの理由でモデルが保存されない場合、事後条件が満たされないため、例外が発生する必要があります。

model.save
-- post-condition: (the model is saved && result == true) ||
                   (the model is not saved && result == false)

saveが実際に保存されない場合、返される結果はfalseになりますが、事後条件は満たされているため、例外はありません。

save!メソッドが非常に単純な事後条件を持っていることは興味深いと思います。

例外を救済するというトピックについては、アプリケーションには例外を救済する戦略的なポイントが必要だと思います。ほとんどの場合、レスキュー/再スローの必要はほとんどありません。救助して再スローしたいのは、ジョブが途中で完了し、何かを元に戻したい場合だけです。そのため、部分的に完全な状態を避けてください。現在の操作が失敗した場合でもプログラムが他の作業を続行できるように、戦略的な救助ポイントを慎重に選択する必要があります。トランザクション処理プログラムは、次のトランザクションに進む必要があります。 A Railsアプリは回復し、次のHTTP要求を処理する準備ができているはずです。

ほとんどの例外ハンドラは汎用である必要があります。例外は何らかのタイプの障害を示しているため、ハンドラーは障害が発生した場合の対処方法を決定するだけで済みます。ハンドラーが例外のポイントに非常に近い(コールグラフに関して)場合を除き、非常に特定の例外の詳細な回復操作は一般に推奨されません。

フロー制御に例外を使用しないでください。そのためにthrow/catchを使用してください。これにより、真の障害状態の例外が予約されます。

(余談ですが、失敗を示すために例外を使用しているため、Rubyではfailキーワードではなく、ほとんど常にraiseキーワードを使用します。Failおよびraisefailは同義語であるため、メソッドが失敗したことをraiseがより明確に表明することを除いて違いはありません。私はnot失敗していますが、明示的かつ意図的に例外を発生させています。これは私が従う文体的な問題ですが、他の多くの人がそうすることはないでしょう。

そこに、例外についての私の考えについてのかなり乱暴なメモリダンプがあります。

同意しない多くのスタイルガイドがあることを知っています(たとえば、 RoboCop で使用される スタイルガイド )。気にしません。ジムは私を説得しました。

4
Karl Wilbur