woshidan's blog

そんなことよりコードにダイブ。

Effective Rubyを読みました

会社の上の方の人から読んだ方が良いとお勧めされたので、4月中ちょこちょこ読んでました。 いわゆるRailserなので、なかなか難しくて山のように付箋が消費されてしまいました。

各章ごとの感想をメモしておきます。

第一章

Railserなので、 Array#compactnilのオブジェクトを除いた配列を返す、や RUBYOPT -w, $VERBOSE = trueで警告を出す、 といったこの辺りから、知らない事がちらほらありました。

Rubyの暗号めいたPerl風機能(特殊グローバル変数etc)の話については、メタプログラミングRubyの例で出てきたなんだか分かりにくいな、 と思っていた部分が「ああ、分かりにくいものだったんだ、あれ」とむしろ安心したり。

定数の定義が、「大文字から始まる識別子」(に対応する値)ということを知らなくて、定数っぽいローカル変数を表すために大文字を使ったらエラーを出したことが懐かしくなりました。

あとは、コードを解釈するときの警告の意味(文法が違う、意味が曖昧、etc)と、実行時の警告(引数がおかしい、メソッドが上書きされた、etc)の違いの下りも面白かったです。

第二章

モジュール、クラスを継承した際のメソッドのルックアップの下りは、用語の定義からきちんと始まっていたのが非常にありがたかったです。

メタプログラミングRubyあたりでなんとなく覚えていた仕組みが、改めて用語が定義を確認できた事でとてもすっきりしました。特に、レシーバと特異クラスの説明が分かりやすかったです。

Structクラスや、superがキーワードであること、その使用上の注意点といった部分は初めて知りました。

レキシカルスコープについて、言葉を聞いた事があるような?程度だったのですが、

レキシカルスコープに関係があるのは、定数が定義され、使われている物理的な位置である。

という説明を見て、何となく分かった気になったりしました。

また、ハッシュで並べ替えが出来るように、#hashメソッド#eql?メソッド#<=>演算子の話を読んでいくとき、 頭が耕されている感じがしました...(笑)

最後の方で、Rubyのprotectedの使い方がよくわからなかったのですが、 同じクラスのインスタンス間でgetterやsetterを共用するのに使われているのを見て少し腑に落ちました。

第三章

  • dup(オブジェクトのコピー(オブジェクトidの違うもの)を返す(オブジェクトの構成要素自体はアドレスだったりする = シャローコピー)
  • clone(dup + フリーズ状態)
  • Marshal(一旦文字列にして構成要素もコピー。ディープコピー)

の違いをはじめて知りました。

さらに言うと、Hash#includes?のほうがArray#includes?より効率がよいという下りを読んでいて、 キーバリュー型のオブジェクトとして使っているけど、そういえばハッシュってもともとアクセスを速くできるように使うものの名前もハッシュでした、みたいな今更な事を思いました。

以下のようなreduceを使っての畳み込み ( = ブロックが前回呼び出された時の戻り値を受け取って、その戻り値を使ってブロックの処理を繰り返す、みたいな) の処理も、はじめて知りました。

def sum (enum)
 # reduceの第一引数(0)はアキュムレータの初期値。
 # アキュムレータはイテレーションの間ブロックに与えられる値
 # ブロックの戻り値が次のブロック実行時のアキュムレータの値
  enum.reduce(0) do |accumlator, element|
    accumlator + element
  end
end

最後の項目で、extend(モジュールのインスタンスメソッドをextendしたクラスのクラスメソッドにする)の使い方を知り、 また、Rubyで委譲を書いてあるのを始めてみて、あ、いままでこういうのJavaでしか見た事無かった感がめちゃくちゃありました。

教科書に書いてある事をもっと実際のコードの中に探しませう、みたいな。

第五章

この辺はどちらかというと、つかわなければいけなくなったときに改めて開く事にして、 それ以外の単純な方法で可能な限り済ませたい気持ちがあります。

それでも、知らないのはよくないですしね。 define_methodのあたりの例をひたすら見た事で、ブロックをメソッドに渡すという事実になれた気がします。

それまでブロックを渡す、ブロックを渡す、と言われても違和感ありまくりだったのですが、 採血用の太い針を見た時の心境から蚊を見かけたときの心境まで下がりました。

引数の数にこだわるProcとこだわらないProcがあるということだけでもしっかり覚えておきたいです。

prependの説明がありましたが、prependについては、 引数のメソッドを継承チェーン内の呼び出したオブジェクト自身のメソッドより手前に置く、 というのはincludeまでの流れをひっくり返してきたなぁ、と思いました。

第六章

require('minitest/autorun')が何をしているかなどの説明が面白かったです。

Minitest::Mock.newでエクスペクテーションを作るとき、まず空のMockオブジェクトを作り、 MiniTest::Mock#expect(:method_name, :mock_response)にて呼び出されるメソッド名と、その戻り値を与えてエクペクテーションを作る。

また、件のメソッド実行後にMiniTest::Mock.verifyで作成したエクスペクテーションがもれなく使われているかを調べる事ができる、というのを読んで、 Mockについて理解が深まった気がします。

効果的なテストの項では、ファズテストとバステストの存在を初めて知りました。手動でひたすらテストするのをエミュレートする印象でした。ハッピーパステストについてはやりがちというか、特に手動確認がそうなりがちなので注意しないとな、と肝が冷えましたね(汗)。

第四章、第七章、第八章

第四章は、Rubyだから、というより、例外を書く時のお作法として勉強になりました。(通信エラーによる例外はしばらく待ってから再送する、再送するまでの間隔は指数関数的に長くしていく、など)

第七章、riやirbのconfの話は面白かったです。たまに覗いてみようと思いました。

bundlerについては、悲しいかな、この章にたどり着くまでにmanのドキュメント見て勉強してしまっていたので、 目新しいところはやや少なかったのですが、 Bundler.require(:group) でグループに登録しているgemをrequireする、 というところが勉強になりました。

第八章は、ガベージコレクタの仕組みの辺りが面白かったです。 ループのなかでオブジェクトを定義しない、というのは、変数を生成すると遅くなるから、と考えていたのですが、変数を生成すると遅くなるのは、ガベージコレクタ(動作時はメインのプログラムは停止)の動く間隔が短くなるからなんでしょうか。

全体として

1つの言語についてがっつり勉強する、という経験が無かったので、めちゃくちゃ読んでてしんどかったです。

でも、良い本でした。

そして、途中から勉強しても勉強しても抜けていくなぁ、ということを思いましたが、 忘れていても一回耕してあるというのだけでも違うという宗教に入っていることにしたので気にしません。

後半力つきている感もありますし、明日からもまたゆるゆる読み直しておこうという感じでした。

余談ですが、この本、Rubyの本にしては結構皮肉めいた言い回しが多くて、珍しくて面白かったです。自分の印象だとRubyの本は、Rubyはすばらしいんだ、ほらほらほらほら、とはしゃぎまくっているイメージがあったもので...。

あと、Rubyの中級者以上の方は、Rubyの初心者がメタプロらしき事をしようとするとき、真っ先にmethod_missingを使いたがる前に、往時のRails tutorialをやったあとに、MinitestとRspecの比較をしてからRspecを選んだかどうか胸に手を当てて考えて、自分はそんなことなかったって人だけが石を投げたらいいと思いました。