こんにちは!kossyです!
さて、今回はEffective Rubyの第4章の覚えておくべき事項を
ブログにまとめてみたいと思います。
前回までの章をまとめたものはこちら
Effective Ruby 第1章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第2章まとめ - その辺にいるWebエンジニアの備忘録
Effective Ruby 第3章まとめ - その辺にいるWebエンジニアの備忘録
第4章 例外
4-1. raiseにはただの文字列ではなくカスタム例外を渡そう
- 例外としてraiseに文字列を渡すのは避けよう。この場合汎用のRuntimeErrorオブジェクトが使われる。そうではなく、カスタム例外クラスを作ろう。
- カスタム例外クラスはStandardErrorを継承し、クラス名がErrorで終わるようにしよう。
- 1つのプロジェクトのために複数の例外クラスを作るときには、まずStandardErrorを継承する基底クラスを作り、ほかの例外クラスはそのカスタム基底クラスを継承するように構成しよう。
- initializeでエラーメッセージを設定するときには、raiseでエラーメッセージを設定すると、initializeのメッセージが上書きされてしまうことに注意しよう。
4-2. できる限りもっとも対象の狭い例外を処理するようにしよう
- 修復方法がわかっている特定の例外だけrescueで捕まえよう
- 例外を捕まえるときには、もっとも限定されたタイプのものを最初に処理しよう。例外の階層構造の上位にあるものほど、rescue節は下流に作る。
- StandardErrorのような汎用例外クラスをrescue節で捕まえるのは避けよう。もしそうしたいと思う場合には、ほんとうに必要なものはensure節なのではないかということを考えるべきだ。
- rescue節で例外を生成すると、新しい例外が現在の例外を押しのけ、現在のスコープを抜けて例外処理を最初からやり直す。
4-3. リソースはブロックとensureで管理しよう
- 確保したリソースを解放するためにensure節を書こう。
- リソース管理を抽象化するために、クラスメソッドでblockとensureパターンを使おう。
- ensure節で変数を使うときには、その前に変数が初期化されているかどうかを確かめよう。
4-4. ensure節は最後まで実行して抜けるように作ろう
- ensure節のなかでreturn文を明示的に使うのは避けなければならない。これが必要だと感じられる場合には、メソッド本体のロジックに何かしら問題があるはずだ。
- 同様に、ensureのなかで直接throwを使ってはならない。throwはメソッド本体で使うべきものだ。
- 反復処理では、ensure節のなかでnextやbreakを使ってはならない。反復処理のなかに本当にbeginブロックが必要かよく考えよう。大抵の場合、逆にbeginの中に反復処理を配置する方が正しいものだ。
- より一般的に、ensure節のなかで制御フローを変更してはならない。制御フローの変更は、rescue節で行うべきだ。その方が、あなたの意図がはっきりと伝わる。
4-5. retryでは回数の上限を設け、頻度を変化させ、オーディットトレイルを残そう
- 無条件のretryを使ってはならない。retryはコード内の暗黙のループとして扱うようにしよう。beginブロックの外側のスコープに境界変数を作り、上限に達するまで例外を再生成するのである。
- retryを使うときには、オーディットトレイルを作ろう。問題のあるコードを再試行してもうまくいかないときには、最終的なエラーまでのイベントの連鎖を知りたいと思うはずだ。
- 再試行の前にディレイを入れるときには、問題を悪化させないようにrescue節のなかで値を増やしていくことを検討しよう。
4-6. スコープから飛び出したいときにはraiseではなくthrowを使おう
- 複雑な制御フローが必要なときには、raiseではなく、throwを使うようにしよう。throwを使うと、ボーナスとしてスタックの上位にオブジェクトを送ることができる。
- できる限り単純な制御構造を使おう。catchとthrowの組み合わせは、単純にreturnでスコープから抜け出すメソッドとそれに対する呼び出しで置き換えられることが多い