アペフチ

『APIデザインケーススタディ』を読んだ

ようやく『APIデザインケーススタディ』を読み終えた。デザインの本なのだけど、僕はRubyの様々な組み込み・標準添付ライブラリーの解説書、またはエッセイとして、主に読んだ。楽しい時間で、読み終わって寂しい。

本当は25日に読み終わったのだけど、昨日はSendagaya.rbのことを書いたので、話題を分けるために今日にした。こういう時、tDiaryが恋しくなる。日記の為のソフトウェアだから、一日に複数の話題を書くことが、自然にできる。

この本は「I/O」「ソケット」「プロセス」「時刻」「数、文字列」の五章で構成されている。個人的にこれを

  • OSとの間を埋める(「I/O」、「ソケット」、「プロセス」)
  • 人間社会との間を埋める(「時刻」)
  • その他(「数、文字列」)

と捉えた。

OSとの間を埋める

RubyのI/Oやプロセスなどに関するクラスは、システムコールやglibcの関数を、インターフェイスは模倣して、内部では呼び出すのを原則としてデザインされている。その中でも、そのままglibcからRubyに移植せず、敢えて異なるインターフェイスや動作にしたほうがいい所があったのでそうした、や、ユースケースを考えるとメソッドを追加したほうがいいからそうした、などの事例が紹介されている。それぞれに調査結果、考察、決断が述べられていて、単なるカタログにはなっていなくてケーススタディする内容があり、面白い。

僕はRubyのユーザーではあるけれど、Cは書けない。拡張ライブラリーは使う一方だし、OSのシステムコールなども直接触ることはまずない。IO#read_nonblockなども、使うことはあってリファレンスマニュアルは読むけど、そこに書いていることで満足して、それでも不明なところは(Rubyプログラムを)動かして確認してから使っていた。この本では、そういった部分のOS側の話なども解説した上で、Rubyではどうしたかと話してくれるので、デザインだけでなく、APIその物の勉強にもなる。「自分が触っている部分の一つ下のレイヤーも理解しておくべきだ」とはよく言われることで、でも中々実践は難しい、その部分を行えるので助かる。

また、余談になるが、ノンブロッキングI/Oという言葉は非常によく聞くし、一応、EventMachineNode.jsなどで使えてはいるつもりだ。でも、下のレイヤーでは、ファイルディスクリプターにブロッキングモードとノンブロッキングモードがあって、ノンブロッキングモードの時にアクセスして読み取り可能でなければこういうエラーになって、という仕組みになっていたことは全く知らなかった。この知識が、直後に読み始めた『nginx実践入門』の最初のほうで活きたので思わず顔がにやけた。

人間社会との間を埋める

第4章は時刻の話。ここはもう、人間側の都合に合わせる話が圧巻。

閏秒があるから将来の日時を正確に表すことは不可能、というのは序の口で、日本にいると、UTCにタイムゾーンオフセットを足せばいいんでしょ? くらいに考えてしまうかも知れないけど夏時間があったらそうはいかない。夏時間、いつから夏時間で、いつまで夏時間か、どのように決まるのか、知っていますか? 僕は知らなかった。「毎年これこれの月のこれこれの曜日」みたいに決まっているのはいい方で、太陰暦に従うとか、その年にならないと政府が決めないとか、ほんと色々ある。夏時間の切り替わりのタイミングでは、存在しない日時や二重に存在する日時が存在するので、日時の扱いは慎重さが必要になってくる。

その他

ここは数値関連の色々な話。ここまで読んでいれば、APIデザインのパターンに少しは慣れているので、なるほどなるほどとさくさく進む章だった。

「終わりに」で

ところで、意識的に使いやすさをデザインするにあたって、具体例と並んで存在して欲しいのは、使いやすさの理論です。理論があれば、個々の具体例がどのような理屈で使いやすさを実現しているか、理解しやすくなりますし、目の前の問題を解決するライブラリをどうデザインするのが良いのか、という見通しを与えてくれるでしょう。さらには、使いにくさという問題を発見することにも役に立つかもしれません。

残念なことに、今のところ、そのような理論で満足できるものはなさそうです。

ということが述べられていた。何気ない文のようだが、最後まで読んだ所で「意識的に使いやすさをデザイン」と言われると、とても重みがある。

『メタプログラミングRuby 第2版』@Sendagaya.rb #134

Sendagaya.rb #134に参加して『メタプログラミングRuby』の読書会をして来た。今日は初参加、それも「最近Ruby始めたばかりで……」とか「プログラミングを始めたばかりで……」という人がすごく多かった。何があったんだろう?

先週に引き続き『メタプログラミングRuby 第2版』を読んだ。

「2.2.5 ネームスペースを使う」から15分みんなで黙読して、その後に気になることなどを話した。この「気になること」が盛り上がって、今日は他のことはしなかった。結構知らないことが書いてあって(第1版読んだはずなんだけど殆ど憶えてない……)面白い。

例えばコラムでloadに触れていた。普通loadは呼ぶ度にスクリプトが実行されるので、定数定義があると再定義の警告が表示されてしまう。ところが第二引数にtrueを渡して

load('defining-constants.rb', true)

と呼ぶと、この警告が避けられる。なぜかというと、「第二引数にtrueを渡すと、無名モジュールが作成され、スクリプトはその中で実行されるから」だと本では説明されている。「なるほどそうなのか、第二引数のこと知らなかった、勉強になったなあ」と、僕はあっさり流していたが、参加者から「無名モジュールってなんですか」っていう声が上がってそう言えば、知らないな、と思った。無名クラス(匿名クラス)はたまに使うのでそこからの類推と、文脈と合わせて勝手にイメージを作って納得していたが、知らない。ということで、デスクトップをプロジェクターで映していたfukajunさんがターミナルを出して、動かしてくれる。みんなで「こういうことかな」「じゃあこういう時はこうなるのかな」などと言っていると、それも全部実行してくれる。こうしてみんなで無名モジュール(anonymous module。僕は匿名モジュールと呼びたい)の理解を深めた。(翻訳の角さんから、無名、匿名についてこんなコメントを頂いた。https://twitter.com/kdmsnr/status/691839083266641920。うーんなるほど、勉強になる……。

その後Classのクラスは? Moduleのクラスは? Moduleのスーパークラスは? みたいな話が出ていて、Ruby始めたばかりの人がぴんとこないということだったのでその解説をしたりもした(tkawaさんが)。

prependは第1版にはなかったこともあってかなり盛り上がった。次の記事を見て老害がノスタルジーに浸りながらalias_method_chainの仕組みを解説したりもした。
Ruby2.0のModule#prependは如何にしてalias_method_chainを撲滅するのか!?

本に戻って、文中、prependに関して、こういう風に動作を説明してくれる。

module M1; end

module M2
  include M1
end

module M3
  prepend M1
  include M2
end

M3.ancestors # => [M1, M3, M2]

prependしたM1M3に差し込まれて、includeしたM2に置かれている。一度継承ツリーに入ったモジュールは二度は入らない。説明の通りだ。では、

module M3
  include M2
  prepend M1
end

と順番を変えたら、M3.ancestorsはどうなるだろうか。実行せずに答えられるだろうか? その答えに、どのくらい確信を持てるだろうか? これも、各々推測を述べた後、「fukajunターミナル」で実行して、回答を得たりした。

こういう、一人で本を読んでいるだけだと見逃しがちなことも、誰かが気付いて声を上げてくれるので読書会中々いいです。ただ(と言っても別に悪いとは思ってないけど)、このやり方は時間は掛かる。ので今日のSendagaya.rbはここで終わった。

次回は

なんかがいいですかねえ、って話をしていたけど、来週その場で決まることでしょう。

ちなみに、今回は開催前日にDoorkeeperのイベントが作成されたけど、次回分はその日のうちに作成されていたので、もう申し込める:
https://sendagayarb.doorkeeper.jp/events/38208

Droongaのインストーラーを直した

Droongaは、しばらくマニュアル通りにインストールできない状態だったので、インストーラーを直してプルリクエストを送った。

(マージしてもらった後に問題に気付いて追加でちょいちょいパッチを投げてもいる)

マージされたものの、今はまだ修正版がリリースはされていないので、それぞれこういう風にVERSION環境変数を指定してインストールする必要がある。

# curl https://raw.githubusercontent.com/droonga/droonga-engine/master/install.sh | \
    VERSION=master bash
# curl https://raw.githubusercontent.com/droonga/droonga-http-server/master/install.sh | \
    VERSION=master bash

リリースされたらVERSION=masterはなくてもインストールできるようになる。

また、マニュアルではserviceコマンドでDroongaの二つのプロセスを管理しているけど、今回のパッチでsystemdを使うようになったので、今マニュアルを直しているところ。来週中にはパッチを送れるはず。

マニュアル通りに入れられないこと自体は認識していて、ワークアラウンド入りのItamaeレシピを作って使っていた(DroongaをインストールするItamaeレシピ)。後ろめたさがあった。スキル的には自分で直せるはずなのにそうしていないのは愚か、問題報告すらしていなかった。今回修正して、受け入れてもらって、喉の小骨がようやく取り除けた気分だ。

恥ずかしながらシェルスクリプトに不慣れで、プルリクエストを送ったあとで、色々指摘してもらいながら直していた。ありがとうございました。

systemdのunitファイルにも不安があるので、こうしたほうがいいよというのがあったらぜひ教えてほしい。