500 円玉貯金が N 万円貯まったので Thunderbolt Display を購入しました。
現在の開発環境の様子です。
画面が広いと Vim で複数ファイル広げたり、ファイル更新時にはその横でユニットテストが自動実行されたり、別のペインで tig や htop を実行しておくこともできるので便利ですね。
あとは最近少女革命ウテナ DVD-BOX を買ったんですが、これも大画面で観られるようになりました。

そんな大画面でつくった gem を紹介します。

Mr. Mongo とは

yuya-takeyama/mr_mongo

MongoDB の MapReduce の定義を Ruby の内部 DSL で記述し、実行するためのフレームワークです。
Ruby で、といっても map/reduce の関数は JavaScript です。

例えばワードカウントであれば、以下のような記述になります。

map/reduce を __END__ 以降に記述できるのが特徴です。
ここでは使われていませんが、finalize も同様に定義できます。

なお、__END__ 以降の読み込みについては先日開発した InlineTemplateLoader を使用しています。

何で DSL が必要か

ひとつは書き方・定義の仕方を統一するため、もうひとつはユニットテストのためです。

書き方を統一する

MongoDB 標準のやり方にしろ、各言語向けのドライバを使うにしろ、そのままだと人によって書き方がいろいろ異なります。
そこにこの Mr. Mongo を導入することで、「1 ファイル 1 ジョブ」というルールが強制されるようになります。

MapReduce をユニットテストするということ

MongoDB における MapReduce のユニットテストについては、ほとんど言及されることが無いと思いますが、やはり重要なんじゃないかと考えています。
上記のような単純なワードカウント程度の例ならともかく、大量のデータを、複雑に処理し、しかも長期的にメンテナンスを行うのであれば、回帰テストとしてのユニットテストが無くては安心できません。

また、テスト駆動で開発することでより効率よく開発できるケースもあるでしょう。

Mr. Mongo でどうユニットテストを書くか

これについては現状でもできなくはないのですが、フレームワークとしてのサポートがまだ貧弱な状態です。
mr_mongo-rspec-matcher なんてのを作って RSpec でのユニットテストをやりやすくする、というアイディアはあるものの、まだ実装できていません。

一応現在のコードベースでも MapReduce のユニットテストはできています
MapReduce をオンメモリで実行し、その結果を連想配列と比較しています。

これをもっとフレームワークっぽいやり方でできるようになれば、いろいろ捗るんじゃないかと思っています。

あと、以前作った mongo_require.js を併用することで、MapReduce ジョブをある程度モジュール化して記述すれば、これもまたメンテナビリティに寄与すると思われます。

まとめ

MongoDB の MapReduce を効率よく開発・管理するためのフレームワーク Mr. Mongo について紹介しました。

おやすみなさい。

, , , ,

2 月はブログを書くことなく終わってしまいました。
3 月も半ばを過ぎようとしていますが、久々のブログ更新です。

ちょいとした Web アプリケーションを書くとき、やっぱり選んでしまうのは Sinatra。
とにかくサクっと作れるし、ファイルとかも少なくて済む。

中でもズボラ的に便利だと思うのがインラインテンプレートと呼ばれる機能です。
以下のように、プログラムの末尾にテンプレートをそのまま書けるというものです。

このインラインテンプレートがそれだけで gem 化されていれば、あらゆるフレームワークや DSL にこれを組み込めるのではないか、ということで作ってみました。

yuya-takeyama/inline_template_loader

inline_template_loader という名前で rubygems.org に登録済みですので、gem コマンドなり bundler なりでインストールできます。

使い方はこんな感じ。

InlineTemplateLoader.load でインラインテンプレートを Hash として読み込みます。

インラインテンプレートを読み込むファイルを load に引数として渡すこともできますが、省略時は caller を使ってバックトレースから呼び出し元を調べて、そのファイルから読み出すようにしています。

これを何らかのフレームワーク等に組み込む場合は、少し工夫が必要です。
普通は InlineTemplateLoader.load をラップして使うことになると思いますが、その場合は上記のように引数を省略してしまうと、ラッパーメソッドが存在するフレームワークのライブラリそれ自体からインラインテンプレートを読み込んでしまうことになります。

それだと困るので、引数に整数値を渡した場合は caller が返す配列のうち、整数値分だけ後の要素を呼び出し元とすることができます。

文だけだと訳がわからないと思うので、例を示します。

まずは DSL を用いた何らかのプログラム。
インラインテンプレートはこのファイルにあります。

次に InlineTemplateLoader をラップして何らかの処理を行う内部 DSL の処理系です。

このように load に整数値 (ここでは 4) を渡すことで、その文だけバックトレースを遡り、DslUsesInlineTemplateLoader.dsl の呼び出し元のファイルからインラインテンプレートを読むことができます。

来週あたりには、これを用いて MongoDB を操作する DSL なんかを紹介できればと思ってます。

そんじゃーね。

, ,