Perl の ORM の代表的なひとつである Teng は DBIx::Skinny の後継にあたりますが、 DBIx::Skinny にあった resultset
に当たる機能が Teng に無いので、 Teng プラグインとして移植したという話です。
モチベーション
気がつけばもう4、5年くらい使っている、個人趣味のための Web インタフェースのツールがあるのですが、最初から適当に機能を拡張していったツケが溜まり溜まって、もはや拡張不能なくらいコードがスパゲッティになってしまっていました。手元のディレクトリでは、リポジトリにコミットしていない宙ぶらりんのファイルの散らかりが、 “行き詰まった” 感を無力に物語っています。
それでも必要なので使っているしこれからも使うつもりなのですが、使っているからにはやはり改良のアイデアがちょこちょこ出てきます。でも、直せない。直せないので、使うたびにイライラが募ります。この状況が健康に良くないのは明らかですから、じゃあ書きなおそうかと思い立ったのが──いつだったか。しかし最近モチベーションが少し上がってきたので、少しづつ手を動かし始めた次第です。
そのツールは外部に公開しないサイトなので、いたる所じゆうです。 WAF は Mojolicious を使って書いていました。 ORM には DBIx::Skinny 。 DBIx::Skinny にしたことに理由は特に無く、当時、仕事の関係で DBIx::Class に辟易していたじぶんはもっとシンプルな、手軽なものがいいなと思っていたところでしたから、しぜんなチョイスだったことと思います。日本語のチュートリアルがあったのも、そして全体像が把握しきれる大きさだったのも、食指を動かす動機になったと思います。
そのツールを作り直すに当たって、 DBIx::Skinny については Teng に置き換えることになります。──当たり前のように述べましたが、その作者自身が DBIx::Skinny に行き詰まりを感じて書き直したのが Teng なので(ですよね?)、つまりその後 DBIx::Skinny はメンテされなくなることが予見できたので、将来性のあるほうを選択することに躊躇う余地はありませんでした。(実際、 DBIx::Skinny は最後のリリースが 2011 年 9 月です。)
課題
ところがいざ移植作業を始めてみると、すぐに課題に突き当たりました。
Teng は DBIx::Skinny の API をすべて受け継いでいるわけではありません。いわゆる単純な CRUD については問題無いのですが、じぶんのツールでは resultset
メソッドが提供するクエリ・ビルダを多用していたのですが、まずこれがありません。また Teng は JOIN をサポートしておらず、これもじぶんでなんとかしなければなりません。などなど。
もちろん Teng の設計ポリシーとしてそれらは事前に覚悟されることではありましたが、いざその場面に直面した時、選択肢としてあるだろうひとつとして SQL の直書き、そしてもうひとつの希望として、プラグインの存在に思いが馳せます。
前者はやりたくないので(そのための ORM ですし)それは最終手段として、さてプラグインを探してみると、 Teng::Plugin::ResultSet という、その名もずばりのものがありました。──が、そう思ったのもつかの間、これはまったく別の代物でした。正直何のためのものかわかりませんでしたが、とにかく違うことは明らかでしたので、ほかを当たらなければなりません。しかし、見つかりません。なければ、──じぶんで書くほかないということになります。
ただ、あまり手間をかけたくない、一から書こうとするには “軽量 ORM” として釣り合いが取れないのでは無いか、ということもあり、いったんは DBIx::Skinny に戻ろうかとも考えました。そこで思いついたのが、 DBIx::Skinny のソースから resultset
だけ移植ができないか、ということです。
実装
中身を見てみると、さいわいなことに見通しが得られました。 resultset
は、 SQL を部分部分で組み立てながら最終的に “生 SQL” の文字列を生成するだけで、とくに DBIx::Skinny のインスタンスに頼っている部分も無く、これをそのまま持っていければ、 Teng でも使えそうでした。ならば物は試しでと、中身を詳しく精査することもせずに、メソッドの部分のソースコードをコピーし、それをテキストエディタにぺたりと貼って、 Teng (のプラグインとしての体裁を整えながら、それ)に持って行ってみたら、なんということか、あっけなく動いてしまったではありませんか。
これはまさしく、 “軽量な ORM” という売り文句、その思想を裏切らない柔軟かつシンプルな設計の賜物に違いありません。
じぶんは名前空間を変えたことと、メソッド名を resultset
から query
へと変更したこと以外は、殆ど何もいじらずにその機能を手に入れることができました。そしてその成果を Teng プラグインとしてまとめました。
SQL 実行後に返却されるイテレータが DBIx::Skinny と Teng とでは、その機能が若干異なるので完璧とまでは言えませんが、それはプラグインの範疇を超えるところです。クエリ・ビルダとしては DBIx::Skinny のオリジナルと比較しても遜色無いでしょう(そう、コピペですから)。
展望
DBIx::Skinny から Teng へ移植することは、これでできそうです。この先もまだ気づいていない問題が出ないとも限らないので油断はできませんが、どんな課題が出ようとも、じぶんが ORM に求めていた “生 SQL” を書かずにいられるという最大の要件を満たすことと比較すれば些細なことに過ぎないので、まずは御の字といったところでしょうか。
また一方で、 DBIx::Skinny からの移植を考えに入れる必要がないのならば、クエリ・ビルダとして SQL::Maker などを使って実装しなおすように検討するのもよいでしょう。
ただ、この Teng についてですが、じつは別の方面での心配が、まだあります。
DBIx::Skinny と比較して「将来性のあるほうを選択することに疑う余地はありませんでした。」と上に述べたところでしたが、 Teng 自身も現在の状況を見るに、あまりその将来性が芳しくありません。これはじぶんの主観なのですが、そのいちばんの根拠は、 Teng のメイン・リポジトリである Github のプロジェクト・ページを覗いたところでは、 ISSUE はあれども活動がほとんど止まっている状況に見えることです。これが意味することは、言うまでもないでしょう。ただ、そもそも Teng ばかりでなくその土台である Perl のいまある状況こそ気がかりにせざるをえない、とも言えるのかもしれません。
そのような現実に直面しながら、その上でなおツールの移植を考えるならば、まずは Perl から脱することを最初に検討するべきなのかもしれません。しかしながら、じぶんの目下の取り組みは、プライベートなツールです。責任のある仕事じゃありませんから、ならば、書いていて楽しい Perl で続けるのがいいに決まっていますから、そういったネガティブな状況についてシリアスに考えることは余計なことなのかもしれない、とも思います。