毎週1冊技術書を読んでブログでアウトプットすることが目標で今回が第22弾です。
今回は、Effective Ruby を読みました。
Rubyの効果的なコードの書き方について詳細に解説している本です。
知らなかった書き方も多く、明日から即実務で使えるとても有意義な技術書でした。
- 第1章 Rubyに身体を慣らす
- 第2章 クラス、オブジェクト、モジュール
- 第3章 コレクション
- 第4章 例外
- 第5章 メタプログラミング
- 第6章 テスティング
- 第7章 ツールとライブラリ
- 第8章 メモリ管理とパフォーマンス
- おわりに
第1章 Rubyに身体を慣らす
-
定数とは、先頭が大文字になっている識別子のことである。クラスやモジュールの名前も実際には定数である
-
定数は書き換えられないようにfreezeすべき。定数が配列やハッシュなどのコレクションオブジェクトは、コレクションとその要素それぞれをfreezeする
第2章 クラス、オブジェクト、モジュール
-
Rubyは多重継承をサポートしていないが、includeメソッドでクラスにモジュールをミックスインすれば、多重継承と同じような効果が得られる
-
Rubyは、メソッドを探すときに、最後にインクルードされたモジュールから順にたどっていく。最後の階層まで探しているメソッドが見つからなかったときには、method_missingを探してもう一周サーチを行う
-
継承階層の上位にあるメソッドをオーバーライドするときは、メソッド内でsuperを使ってオーバーライドされるメソッドを呼び出すことができる。引数もかっこも付けずにsuperを呼び出すと、呼び出し元のメソッドに渡されたすべての引数を渡してオーバーライドされるメソッドを呼び出すという意味になる。オーバーライドされるメソッドに引数を渡さずにsuperを使いたい場合は、super()のように空のかっこを使う必要がある
-
セッターメソッドは、明示的にレシーバを指定しなければ呼び出せない。レシーバがなければ、変数への代入と解釈されてしまう。インスタンスメソッドからセッターメソッドを呼び出すときには、レシーバとしてselfを使う
-
新しいクラスを作るほどでもない構造化データを扱うときには、HashではなくStructを使うようにすべき。Struct::newの戻り値を定数に代入し、その定数をクラスのように扱う
-
トップレベル定数を修飾なしで使うと曖昧になるときには、”::”を使ってフルに修飾する(例 ::Array)
-
equal?メソッドは、厳格にオブジェクトを比較し、両方が同じobject_idを持たない限りtrueを返さない
-
2つのオブジェクトが同じ値を表すかどうかをテストするときには”==“演算子を使う
-
Rubyがprivateメソッドに加えている制限は1つだけで、privateメソッドは明示的なレシーバを指定して呼び出すことができないことである
-
protectedメソッドは、関連するクラスの間でプライベートな情報を共有するために作られる。レシーバを明示してprotectedメソッドを呼び出せるのは、同じクラスのオブジェクトか共通のスーパークラスからprotectedメソッドを継承しているオブジェクトだけである
第3章 コレクション
-
Rubyのメソッド引数は値渡しではなく参照渡しである。ただし、この規則には、Fixnumオブジェクトという例外がある
-
reduce(inject)は、関数型プログラミングの世界で畳み込みと呼ばれる関数で、あるデータを別のデータ構造に変換する、非常に強力な関数である
-
以下例の動作は、イテレーションのたびに、ブロックは現在のアキュムレータと現在の要素を受け取り、それらを加える。この和はブロックの戻り値になり、次のイテレーションのアキュムレータになる。このプロセスは、ブロックにすべての要素が渡されるまで繰り返され、reduceはアキュムレータの最終的な値を返す
enum.reduce(0) do |accumulator, element| accumurlator + element end
-
reduceを使えば、よく使われるmap・selectなどを使うよりも効率の良いコードにできることがある。reduceのブロックは、新しいアキュムレータさえ返していれば、与えられたアキュムレータと要素に何でも自由に操作を加えられる
第4章 例外
-
raiseの第1引数としてクラス名を指定できる。その場合、指定されたクラスの例外オブジェクトを作り、それを使って例外を生成する。クラス名を指定しない場合、RuntimeErrorクラスとなる。第2引数(オプション)はエラーメッセージとして使う文字列を渡すことができ、指定しない場合はクラス名となる
-
修復方法がわかっている特定の例外だけをrescueで捕まえるようにする。例外を捕まえるときは、もっとも限定されたタイプのものを最初に書く
-
StandardErrorのような汎用例外クラスをrescue節で捕まえるのは避ける。操作を加えたいときは、ensure節で代用できないかを考える
-
rescue節の中で例外を生成するときは、raise(e) のようにして元の例外をraiseする
-
例外が発生するかもしれないときは、確保したリソースを解放するためにensure節を使うとよい。ensure節は正常な条件でも例外条件でも実行される
第5章 メタプログラミング
第6章 テスティング
-
テストを書くときは、失敗するようなテストを書く。コードの重要な部分をコメントアウトし、その部分のテストが失敗するようにする
-
バグの根本原因を探し始める前にそのバグのために失敗するテストを書く。バグフィックスの最初のステップはバグの再現であり、そのバグの専用のテストを用意すれば、フィックス後に再度バグが発生することを避けられる
第7章 ツールとライブラリ
-
Bundlerは、gemの依存を自動的に管理し、開発中に使っているgemセットとまったく同じものを他のデベロッパーや本番サーバも使うようにしてくれる。必要なgemは、Gemfileで指定する。Bundlerは、指示を受けると必要なすべてのgemとそれらの依存関係をインストールする。また、依存全体を格納するGemfile.lockを作成、更新する
第8章 メモリ管理とパフォーマンス
-
パフォーマンスの低いコードを書き換えるときは、まずプロファイリングツールを使って状況を確認するべき
-
ループ(eachブロックなど)内で使うオブジェクトが書き換えられないのであれば、オブジェクトリテラルを定数とすることで、メモリ確保の回数が減り、ガベージコレクタが起動するリスクを下げることができる
おわりに
ここまで読んでいただきありがとうございます。
本書にはコードを用いた具体例が多くてとても分かりやすかったので、気になる方はぜひ本書をご覧ください。
次は、リーダブルコード を読む予定です。
来週も頑張ります!