Akasaka.rb/Rails勉強会@東京のTDDペアプロセッションでLRU Hashをつくりました

今日はRails勉強会@東京41.1会がありまして、その中でAkasaka.rb提供、http://twitter.com/t_wada 先生id:t-wada先生を招いてのTDD/ペアプロセッションがありました。

お題は「LRUぽい動き、つまり最近使ってない要素を消していってメモリ爆発を防ぎつつ、それなりにキャッシュストアとして使えるHashのようなもの」が欲しい、というものです。詳しくは相沢さんが書いてるhttp://d.hatena.ne.jp/ayumuaizawa/20090621を参照のこと。

で、今回すごくよかったのは前半セッションでペアプロをやったうえで、後半セッションはみんなでそれをコードレビューするというもの。ついさっき真剣に書いたものだから記憶が新しいし、8ペアくらいあったのでバリエーションにも富んでいるしと、凄くいい構成でした。ペアプロと、出来たコードをみんなで愛でる、この相性の良さはヤバイ。

つくったLRUHash

私はid:fistfvckさん(ですよね? お名前確認してなかったのでちと不安)と一緒にコードを書きました。仕様はこんな感じ。

Hashぽいインターフェースが欲しいとの要件だったので[][]=をまずは実装(上2つのexample)、その後100個という最大値を挟んでのLRU的機能を実装してみました。実際のストレージは、ふつうのHashへのdelegateで。継承したペアも多かったんですが、私たちは「コレはis-a Hashじゃなかろう」ということで委譲を使ってみることにしました。Forwardableは凄く便利。
このあたりのテストを書いてみると、LRUぽい機能は=で何かやれば良さそうだぞ、というのが導出されてきます。また、テストを書いてみると、実際のクライアントとしてはcacheされていてnilなのか、そもそもキャッシュされていないのかを見るためにhas_key?系のメソッドも欲しかろう、ということもわかったので、そっちも委譲しています。

で、プロダクトコードは以下です。もちろんRuby 1.9でテストしています。

https://gist.github.com/133521/82178f453987fff450b9a97ac7e689e0a43e15f0

順序が保持されるHashなんて気持ちわるい、そう考えていた時期が私にもありました。コレはたしかに便利。ビミョウだけど。

その後、プロダクトオーナーであるid:t-wadaさんより「Railsで使いたいので1.8で動かないか』という指摘をいただきました。それをうけて1.8用に書き直したのが以下のコードです。仕様変更だー! ワーン。

例外系とかいろいろ省いていますが、Rubyって簡単に書けていいですね。