ブロックによるRuby内DSLの起源

言語内宣言的DSLを構築するRubyの能力がいつからできたものなのか、ふと疑問に思った。

この手の記法で一番古くからあるものとして思いつくのはTk bindingだが、これはいつ頃からあったんだろう。 そう思って古いRubyを見てみた。fj.sourcesにて最初に世界に向けて流されたというruby 0.9.5を見てみると、sample/tkhello.rbに次のような例が既にある。

TkButton.new {
   text 'hello'
   command proc{print "hello\n"}
   pack('fill'=>'x')
}

MatzがLispを意識していて1LispDSLが盛んに構築されていたことを考えると、これはMatz単独の発明ではないかもしれない。でも、この時点で既にブロックというRubyの機能を用いて宣言的にものを記述するという発想はあったことは分かる。

たとえブロックという制御構文を自作するための記法があったとしても、宣言的語彙を構築するという意思がなければAPIはこんな感じの筈だからだ。

TkButton.new {|btn|
   btn.text = 'hello'
   btn.command = proc{print "hello\n"}
   btn.pack = {'fill'=>'x'}
}

ChefやVagrantfileRSpecといった現代のDSLを知っているとすこし物足りないのは確かであるものの、基本的な形はRubyが最初に一般に投稿された1995年の時点で完成していたことが分かる。

ただし、この発想が更に一歩進んで臨界点を超えて広まり出すにはRakeを待つ必要がある。そして、最後の部品である表現能力のさらなる探索はRSpecによってもたらされたと言うべきであろう。


  1. そもそもRubyにはMatzLispというあだ名があったわけだけど、割とあとのほうになるまで、nilが空配列と同等に扱われるケースが広く残っていたりというあたりが思い当たる。

Corporate Reliability Engineering

最近、SRE - Site Reliability EngineeringのアナロジーとしてCorporate Reliability Engineeringというのを考えられないかみたいな話を社内でしている。

SREは伝統的なシステム運用チームの仕事を再定義したものだ。SREはシステムの安定だけを至上目的にするのではなく、際限なく増え続ける運用タスクを真面目にこなすことを目的にするのではない。開発チームを巻き込んで適切なシステム安定度を見いだし、より少ない手間でシステムを安定運用するための開発を自ら行なう。運用のルーチンワークに費やす時間を全体の50%に抑えるように努力する。そして残り50%で今後もその配分を保つ為の開発や、更に上を目指すための仕組み作りを行なう。

同じ発想は業務システムや社内セキュリティ、更にはコーポレート部門にも適用できるのではないか。つまり、業務システムを運用して社内業務を回すとか社内セキュリティを保つ業務、あるいは人材を募集したり経費を処理したり業務についても、際限なく増え続けるタスクを間違いなくこなすことを目的にしないやり方があるのではないか。 相対する部門と共同でより少ない手間で適切なエラーレートを保って回していく仕組みを作り続けるのが重要で、それに時間の50%を使うべきではないか。

うちの会社はWeb系スタートアップ文化から出発している一方で、急速に規模を拡大している関係上で管理すべき物はしっかり管理する必要に迫られている。そこで、管理が物事を堅苦しくしたり管理コストが線形以上のオーダーで爆発したりしないためには、SREの思想が必要なんではないか、という話を最近している。

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

はてなブログに引っ越した

ここ何年か自作のブログシステムrhianoletheでブログをホストしていたが、とうとう耐えきれなくなったので、はてなブログに引っ越した。 主なリソースについてはすべて旧URLからのリダイレクトを提供しているつもりだが、取りこぼしがあったらアクセスログを見ながら適宜修正していこうと思う。

耐えきれなくなったのは、この数年のwebフロントエンドの発展と私の専門領域の乖離が原因だ。まず第一に、数年というもの私が専門にしてきたのはバックエンドだった。 一方、この期間においてデバイスの多様化やフロントエンド技術の発展がめざましく、こちらはこちらで専門化が進んでいったため、もはや個人が片手間に商用水準のフロントエンドをこなせる時代ではなくなってきている。少なくとも私には無理になってきたし、そこは私にとって重要な注力領域ではなくなった。

そういうわけなので、しばらくはてなブログでやっていこうと思う。 それにしても、はてなブログはカスタムドメインHTTPS対応がいつできるようになるんだろう。

Jsonnetでwebアプリケーションの設定ファイルをテスト可能に

最近、Jsonnetを用いてwebアプリケーションをデプロイする際に適用する設定群をテストしようとしている。

今やInfrastructure as a Codeと言われて久しく、アプリケーション配備の基盤構成もその上で走るwebアプリケーションをどうやって設定するのかもコードとして書かれるのが一般的になった。 それらはコードとして書かれているのでバージョン管理可能であり、テストも可能である。だから何かが間違っていれば実際に配備する前に気づくし、それでも間違えていれば差し戻せる。

「どうやって設定するか」はコードになった。では「何が設定されるか」はコードになっているだろうか。やっている人もいるだろうけれども、そんなに簡単な話でもない。 実際Chefで設定ファイルを扱う際は templates なり files なりが第一の選択であるとは思うが、これらはよほどヘルパーメソッドを充実でもさせない限りそこまでモジュール性を提供してくれない。

そこでJsonnetなのである。詳細は 別記事 に譲るが、JsonnetはJSONやINI形式の設定ファイルを生成するための純粋関数型言語である。これを用いれば、たとえば運用環境ではログローテーションを合わせて設定するが開発環境ではしない、といった差異を抽象化しておいて複数のアプリケーションに一貫して適用することができる。最近試みているケースでは、あるアプリケーションの設定 config が与えられたとき、次のように書くと開発環境の設定を出力する

util.environment.dev(config)

これを運用環境用に差し替えるには次のようにする。

util.environment.live(config)

開発環境と運用環境の設定は同じ config から派生しているので、ユーティリティ関数が生成する差異を除いて両者が一貫していることが保証される。 また、 util.environment.devutil.environment.live がしっかり書かれてテストされている限りにおいて、特定のアプリケーション用設定でうっかり運用環境用の何かを設定し忘れるということもない。

さて、ここでユーティリティ関数群をしっかりテストしなければならないという問題が発生する。そこでJsonnet用のunit testライブラリ JsonnetUnit を書いた。

アプリケーションの実装をテストするのは当たり前だ。どうやって設定を適用するかをテストするのも当たり前だ。今後は、どんな設定が書かれるか、運用環境と開発環境で何が違っていて良いのかをテストしていきたい。

情報技術による変革の道のりを思う

祖父母と話していて、ちょっと調べて本を読んで考えれば分かることに対してなぜいつまでも堂々巡りの思考を巡らしているのだろうと思うことが良くあった。 学生時代に工場生産や農業にかり出されてあまり教育を受けられなかったというのはあるが、それにしても祖父は戦後に大学を出ている。時代的な教育の問題だけとも考えづらい。

しかし、よくよく考えてみるとちょっと調べるために私が使うのはインターネットの情報だ。書籍は書籍の価値があるので同様に情報源とする(今は過渡期で境界が曖昧とは言え、やはり書籍の形に手間暇掛けてまとめ上げた有料情報ならではの価値というのはある)が、それにしたって書籍に到達するのはweb上の書評経由であることも多い。入手経路も半数はAmazonからだ。これらを通じて学んだ情報や考え方、情報の取捨選択の方法に基づいて私は考えている。

これらはどれも祖父母が持っていない物だった。自分が何を知らないのか俯瞰しようとすれば、いくつもの紙の書籍を図書館で読むしかない。しかしこれらはちょっとした話題についての検索効率ではwebに満たない。司書に検索支援を頼もうにも我々がwebで検索するほど気軽にできることではないし、地方の図書館員に占める司書資格者は多くないし、そもそも足が悪くてはそうそう図書館にも行けない。webがなくては、webのみならず書籍や雑誌にすらろくにアクセスできない。情報を得るための情報や情報を抽出するための情報からも隔絶されていく。

ほんの二十数年ほど前まで、インターネット技術は一般的ではなく、社会の殆どはこんな状況だった。知らない間に我々はずいぶん遠くまで来たようだ。

APIデザインケーススタディ —— Rubyライブラリを移植する前に読む本

APIデザインケーススタディ 』という本を頂戴したので読んでみた。

ライブラリ作者に向けて

この本はRuby標準ライブラリを題材にして、分かりやすく、多様な機能をサポートして、互換性を保つAPIの設計をするにはどのように考えるべきかを教えてくれる。

ここでAPIと言っているのは、一般的なRubyのクラスとオブジェクトとメソッドから成るライブラリをどうデザインするか、という話である。 別にChef RecipeやRSpec DSLのようなちょっと変わったDSLを設計するとかそういう話ではない。確かにその種の言語内DSLのデザインには固有のセンスが必要とされるし、 Ruby DSL Handbook なんて本が書かれているように実装にあたってもある種のテクニックが必要なのも確かだ。でも、それ以外の「ふつう」のライブラリのデザインは果たして簡単だろうか。 適切な粒度のクラスを定義する。必要な機能に合わせてメソッドを定義する。メソッドの引数は何であるべきか。引数の順序は? 引数が多すぎて使うのが大変になっていないか。そのメソッド名は他の似た機能から類推可能だろうか。機能を追加するとき、どうやって後方互換性を保てば良いのか。互換性を破ってでも改善すべきと判断するにあたっては何を考慮すれば良いのか。 本書が扱うのはそうした話題だ。

ちなみに、著者のakr(田中哲)さんはRubyライブラリ設計の第一人者と言っても良いだろう。 長くに渡ってRubyコアおよび標準添付ライブラリの開発を幅広く手がけており、今のRubyコミュニティにあるライブラリ設計の慣習を基礎づけた人々の1人だ。 中でも本書で題材に上がっている IO クラスや Time クラス、および socket ライブラリの設計において、いくつもの困難な課題を解決してきた。

本書を読むことで題材になっているRubyの標準ライブラリへの理解は深まるだろうし、自分でRubyライブラリを書くときの考え方の参考にもなるだろう。 もっと一般に任意の言語でライブラリのAPIをデザインするときの助けにもなるだろう。

ライブラリ移植者に向けて

本書はまた、ライブラリを移植する物語として読むこともできる。

Rubyの標準ライブラリ、ことに IOsocket はC標準ライブラリやUNIXシステムコールを意識してデザインされている。 よってこれらのライブラリをCからRubyへの移植と捉えることもできるだろう。

このようなライブラリの移植に当たっては、幾つものデザインの選択肢がある。一番単純なのは、元のライブラリのAPIを引き写すことだろう。 利点としては元のライブラリを知っていれば移植先の学習が容易なことが挙げられる。それにデザインにあまり頭を使わなくて済む。 一方で、これは一般にあまり使いやすいAPIにはならない。 言語ごとに望ましいエラーの返し方も関数の命名慣習も異なるし、そもそも慣習を支える言語の特性自体が静的型付けの有り無しから真偽値の定義から何もかも違うのだ。

その対極に当たるアプローチは、ほぼ同じ機能を提供するライブラリをゼロからデザインすることだ—— もはや「移植」とは言いがたいかもしれないが。 利点としては、もし適切にデザインできれば移植先の言語のプログラマにとって理解しやすく使いやすいAPIが得られる。 一方で、移植元のライブラリデザインからの類推が働かないので学習コストがかえって高く付く可能性もある。

ではRubyは、akrさんは、この両極の間でどのような選択をしてきただろうか。本書はその歴史を語っている。

よりよい移植をめぐって

話は変わるが、私はこの数年というもの、業務ではRuby以外の言語で開発をすることが多い。 もっぱらC++PythonやGo, 時にはJavaを触り、やむを得ずPHPを触ることもある。

これらの言語で開発する過程でしばしばRubyのライブラリやフレームワーク、ツールから影響を受けたと思しきものを目にすることもあった。 ことに各所へのRailsActiveRecordの影響は著しいものがある。昨今ではRailsが常にWebアプリケーション開発の第一選択肢とは限らなくなってきているのも、ひとえにRailsの良さが他のフレームワークに広く受け入れられてもはや現代webアプリケーションフレームワークでは当たり前の性質となっているからである。

このようにRubyコミュニティの成果が他から参考にされるのは誇らしくもあるが、一方でうんざりさせられることもある。 うんざりするのは、Rubyのライブラリやフレームワーク劣化コピーを目にするときだ。

たとえばRails劣化コピーである。 いまどきRailsに影響を受けたフレームワークは珍しくないが、さて、果たしてそのRailsの機能は本当にその言語に向いているだろうか。 そもそもRailsフルスタックかつ密結合な極端なフレームワークとして登場した。Railsには(当時のwebアプリケーションの)すべてが揃っていて、その構成要素が密に結合している代わりに「Railに乗っている」限りにおいては極小のコード量であらゆることが簡単にできた。 普通に考えれば構成要素が密結合なのは悪だが、Railsは密結合由来の難点をうまく補うような機能を提供していて、またRuby自体の柔軟性をもって(いざとなればモンキーパッチしてでも)問題を解決することができる。 あんなにも密結合なフレームワークがまともに使い物になること自体が信じがたいけれども、うまいバランスとRubyの力で不思議と使いやすいのがRailsである。

だとすれば、Rubyよりも柔軟性に劣る大抵の言語にとってRailsの採った選択は適切でない。また、「Railsのサブセットを移植した使いやすいフレームワーク」というのも難しい。全体が揃ってうまくバランスが取れているのがRailsだからだ。 Rubyよりも実行時の柔軟性に欠けるその言語にはRubyよりもよい型安全性があるかもしれない。その言語では標準的なORマッパーがActiveRecordと異なるデザインかもしれない。それならば、おそらくRailsとは違うデザインが向いているはずだ。 それにも関わらず 「Railsをgoで書きました」「RailsPHPで書きました」という類のデザインにはうんざりさせられる。

Rubyのactive_recordライブラリもまた多くのフォロワーを持つ。 しかし思い出して欲しいのは、そもそもの PofEAA ではActive Recordの適用領域は限定的だとされているし、active_recordライブラリはActive Recordパターンより遥かに多くのものを提供しているということだ。 active_recordライブラリやそれに依存するRailsが複雑なアプリケーションを書くのにも使えるのは、そうした拡張機能や様々な細かい配慮、定義済みのRakeタスクのお陰である。 これらなくして、ただactive_recordに影響を受けてActiveRecordパターンを複雑なアプリケーションに採用するのは無謀きわまる。

さて、ではどうすれば良かったのだろうか。そのヒントを本書に見ることができるだろう。 本書はRubyのライブラリは何を考えてデザインされているのかを解説している。またライブラリ移植の事例を豊富に提供している。 よって、何がRuby固有で、何かを移植するときは何を考慮しなければならないのかを学ぶのにうってつけである。

ああ、Goのあのライブラリの、PHPのあのフレームワークの、Pythonのあのツールの作者が安易にRubyのやり方を流用する前に本書を読んでいてくれたら、あれらもまともに使える代物であったろうにと思わずにはいられないのだ。

次世代webカンファレンス

次世代webカンファレンス のserver_archセッションでお話することになった。 イベント趣旨にある「答えの出ていない問題を登壇者が話し合う」というのが面白そうであり、当日はどのように話が進むのか私も楽しみにしている。

私としてはやはり最大の持ちネタはgRPCで、gRPCを使うようなサーバーサイドアーキテクチャはいかなる物なのかというところから切り込んでいくことになるだろう。