Zip/Ruby、File、抽象化

open(path) do |f|
  Zip::Archive.open_buffer(f.read)

上のようなコードをWebで見かけて「なんでFileオブジェクトを受け取れないんだっけ?」としばし考え込む。
それで、Fileオブジェクトから実体(FILE構造体、またはファイルディスクリプタ)を取り出せなくてこんなことになったと思い出す。そういえばRubyのコードをあさっていたような記憶がある…
別に内部でFile#path()やFile#read()を呼び出すようにしてもいいんだけど、前者はいまopenしているモノじゃないのが気持ち悪いし、後者はread()してrewind()してなかったらどうなるんだと思って、結局Fileオブジェクトを引数に渡せないことにした。

それでまあ、自分がライブラリを作るときは抽象化が漏れるのをなるべく避けるようにしていることに気がついた。
つまり上の例だと「FileをArchive.openに渡したけどファイルが壊れてるって言われる。explzhだとちゃんと開けるのになんでー?」みないな抽象化の漏れを避けるために、あえて(一見すると)便利なメソッドを提供しないわけだ。

抽象化が漏れそうなときに取る行動は三つ。

  1. 目をつぶる(そんなことは滅多にないよ)
  2. 抽象化のレイヤを下げる(必要なメソッドは全部提供するから自分で何とかしてくれ)
  3. 抽象化が漏れないようにする(つまりメソッド名に嘘偽りない動作をするようにする)

嘘をつくのもはばかれるし、かといって完璧な実装を提供する技術力と忍耐力がない自分としては、だいたいは2.を選ぶ。

なんとなくだけど、オープンソース界隈(あるいは僕の観測しているRuby界隈)でも同様に2.が選ばれることが多い気がする。ユーザ「なんで便利メソッドがなんですか?」ライブラリ作者「いずれトラブるからだ」みたいなやりとりをいろんなとこでみたような。気のせいかもしれないけど。

Railsはそこんとこはだいぶうまくやっている。好きになれないひともいるみたいだけど、概ね支持されているように見える。

機会があればその辺の思想を他のライブラリ作者さんに伺いたいものだ。コアなZipライブラリは知ってる限りだと他に2つくらいあるけどAPIの設計が全然ちがうんだもん。