Quantcast
Channel: 八発白中
Viewing all 74 articles
Browse latest View live

コマンドラインからHyperSpecを開くRoswellスクリプト

$
0
0

コマンドラインからHyperSpecを簡単に開けるRoswellスクリプトを作ったので紹介します。

Roswellが何か知らない人はまずこちらの記事をお読みください。

blog.8arrow.org

昔はEmacsからemacs-w3mで開くことでEmacsから出ずに見られるように設定していたのですが、慣習として定着しなかったので最近はこのスクリプトでターミナルから開いています。

これならGUIのデフォルトブラウザで開けるので、Slackで質問されたときとかに「HyperSpec見ろ」と言ってURLを投げつけたりできて便利です。

インストール方法

Roswellをインストールしてください。

その後、上述のgistページからダウンロードして実行属性をつけ、PATHの通ったところに置くだけです。

$ wget https://gist.githubusercontent.com/fukamachi/3510ea1609c1b52830c2/raw/clhs.ros -O clhs
$ chmod u+x clhs
$ mv clhs /usr/local/bin

起動時間が気になるようなら、ros buildでexecutableを生成してしまえば待ち時間がほとんどなくなるのでおすすめです。

$ ros build clhs.ros
$ mv clhs /usr/local/bin

Roswellスクリプトにすると、こうして簡単に実行ファイルを吐けるので便利です。

使い方

clhsコマンドにシンボル名を与えるだけです。シンボルが見つかればデフォルトのブラウザでページを開きます。

$ clhs handler-bind
Opening "http://www.lispworks.com/documentation/HyperSpec/Body/m_handle.htm"

仕組み

初回にHyperSpecのシンボルリストのページを取ってきてパースしています。パースしたものは~/.cache以下に保存しており、次回以降はそのキャッシュを参照します。

キャッシュを作るために依存ライブラリとしてDrakma、Plump、CLSSが必要なのですが、一度キャッシュを作ってしまえば毎回ロードするのは無駄なので、キャッシュがないときだけこれら依存ライブラリがロードされます。この仕組みのためにQlotで使っているマクロwith-package-functionsをコピってきていて、その部分だけ少し技巧的です *1

Drakmaのリクエストが200以外を返したときは地味にデバッガからリトライができる、とかも対応しています。Common Lispのrestartの簡単な使い方として参考になるかもしれません。

真似して欲しくないところとしては、terminateにチルダを含むメッセージを渡すことが考えられてないことですが、スクリプト内で使うだけなのでわざわざエスケープ処理はしていません。

ソースコードは以下に貼り付けておきます。ライセンスはMITです。どうぞご利用ください。

*1:このマクロが必要な理由は、Common Lispのリード時エラーを防ぐためです。たとえばDrakmaがロードされていない環境で、シンボル drakma:http-request を含む式をリードしようとすると、Common Lispのリーダがパッケージを探しにいってエラーを吐きます。


Common Lispのコミュニティ事情

$
0
0

初対面の人と二人きりで話すという機会はあまりない。

「普段どんなお仕事をされてるのですか」

──もし訊いても良ければ。そう遠慮がちに言い添えた彼は、コタツを挟んで斜め向かいから好奇心旺盛な目でこちらを見ていた。

プログラマですよ」

そう答えてから、それが十分な情報にならないことに気づいて、「Webアプリケーションとかを作ります」と慌てて付け加えた。とはいえ、それでも大した情報量ではない。

彼はそれを聞いて感心したような表情を作ってからもまだ何か僕の言葉を待っているような様子だったが、僕がそれ以上は口にしないのを感じ取ると言い訳するように言った。

「いや、平日に急に三連泊なんて珍しくて」

その日唐突に山口県萩市を訪れることにしたのに大した理由があったわけでもない。この町は吉田松陰高杉晋作のふるさととして知られる。今も古い城下の残るちょっとした観光地だが、日本海側に面しており新幹線の停車駅からも空港からのアクセスにも恵まれず、訪れる人はそれほど多くない。いつか行こう行こうと思ってなかなか機会を得なかった土地だ。心が決まったのがたまたまこの三月だったというだけだった。普段から仕事は自宅でしているし、自宅に限らずどこにいてもリモート勤務ができる。数日の間、萩でする仕事も悪くあるまい。

「普段から自宅で仕事していますからね。実際どこにいたっていいんです」

東京のIT企業でもまだ浸透しているとは言えないリモート勤務について、この観光地でゲストハウスのオーナーをしている彼に理解が及ぶかという不安もありつつありのままを言ってみた。しかし、意外にも彼は納得したようだ。

「知人にもそういう人が何人かいます。プログラマでね。物を作ってメールで送ればいいんだそうです」

彼にはさまざまな「知人」がいるようだ。考えてみれば自然なことだ。ゲストハウスは多くの人が訪れて一夜して去っていく。宿泊客同士はなんらかの偶然で一時を共有する。多くの人の体験や思想が集って拡散していくハブとしての役割をゲストハウスはしており、各地に広範なネットワークを作っている。彼自身も旅好きのようで、冬の休みに観光に行く際は各地のゲストハウスを訪れて情報を得たりしているらしい。自分には全く馴染みのない世界である。

その日は僕の他に宿泊客はいなかった。障子を通して中庭の柔らかい光が居間に広がっている。平日の昼にゲストハウスに人がいる、というだけで珍しいのかもしれない。彼は視線を手元のPCに移しながら尚もひとりごとのように言った。

「それなら、ほとんど人と会う必要もないでしょう」

彼の意図するところがわからなかったが、僕はそれに答えて言った。「まあ、たまに決まった人とは会いますけれどね」

決まった人。顔が浮かぶのはよく会うCommon Lisperたちだった。「たとえばこの前の週末には友人を僕の家に呼んで、話をしたりお互いのプログラムについて意見を言い合ったりしました」

ほう。彼は顔を上げて意外そうに言った。「プログラマもそのように一箇所に集まったりするんですね」

プログラマといえば日がなコンピュータに向き合って、人にはあまり興味がないというステレオタイプが彼の頭にあるのかもしれない。もしくはすべてをWebで完結すればいいという先進的な人種だと思っているのだろうか。いずれにしても、正解からは遠い。僕は彼の方に向き直り、ゆっくりと言葉を選びながら言った。

プログラマというのは世間で思われている印象とは違って、存外に社会的な生き物なんですよ」

僕は周りで日常的に為されているオープンソース活動について話をした。プログラムを書くときは大抵一人だ。けれど、作ったプログラムを他人にも使ってもらいたいと思う。それを公開する。そこで賞賛や批判を得る。そうすると、それを一緒に改善しようという動きが出てくる。そういった独特の社会性が、プログラマの間では構築されている。

どれだけ伝わったかはわからない。けれど、彼はそれを静かに、ところどころで相槌を打ちながら聞いていた。

「積極的な人だと週末などに勉強会のようなものを開いて、新しい技術を一緒に学ぼうという活動もありますよ」

もちろん、個人的にはむやみに人に会うことは好きではありませんがね、と僕は少し笑って見せた。

今思えば彼にとって不思議だったのは、仕事では人に会わないという選択を良しとしておきながら、週末にはわざわざ人に会おうという二面性にあったのだと思う。だとすればその疑問には全く答えられていないわけだが、彼もそれ以上詳しく訊こうとはしなかったのでうやむやのままである。

Shibuya.lisp

とはいえ、ここ数年はあまり積極的にいろんな勉強会に参加することはしなくなった。唯一渋谷のLispコミュニティ「Shibuya.lisp」にだけはできるだけ参加し、まとまったネタがあれば発表するようにしている。

Shibuya.lispPerlコミュニティの「Shibuya.pm」にインスパイアされてhigeponさんやg000001さん、naoya_tさんを中心に作られたLispコミュニティだ。Common Lispに限らずLisp方言を全般に扱う。

当初は「Technical Talk」という、聴衆を多く集めてLispに関する発表を皆で聴くというスタイルのイベントを数ヶ月置きに開催していたのだが、最近では毎月開催の「Meetup」という小規模なものをメインに運営されている。

「Meetup」は毎月一度、平日の夜に渋谷のサイバーエージェントの会議室を借りて開催される。参加者と発表者はWebで募集され、毎回二〇人ほどが参加する。独特なのは月替りでテーマとなるLisp方言が変わるという趣向だ。Common LispSchemeClojureが順繰りにしばらく回っていたのだが、今年一月を最後にSchemeの参加者不足によりScheme回はスキップされており、今はCommon LispClojureが交互にテーマに選ばれている。

小規模ながらUstreamでの同時配信と、開催後の録画の公開も行っており、この点は非常に意欲的だ。これから参加しようか迷っている人はまずはShibuya.lispのWebサイトを見てみることをお勧めする。

知らない人も多いかもしれないが、実はShibuya.lispの運営は数年前にすっかり入れ替わっている。Technical Talkの定期開催も途絶えて二年ほど経った頃、g000001さんの提案により運営の見直しがなされたときに運営を担っていた人々は解散した。それと同時に、Shibuya.lispの継続を望む人々が手を挙げ、新たに第2期Shibuya.lisp運営チームが組織された。今Shibuya.lispを運営しているのはその人たちである。

新しい運営の最初の仕事はコミュニティの運営方針を考えることだった。今までの運営チームと同じである必要はないし、メーリングリストには新しいメンバーでできそうな意欲的なアイデアがいくつか挙げられていた。が、当然ながらそれらの方向性は、考えたメンバーによってバラバラだった。

メーリングリストで手を挙げただけの、互いに顔を合わせたこともない人々で話をまとめるのは難しい。特に、これからの運営どうしましょうかね、といった曖昧な内容をメールのやり取りだけでまとめるのは至難だろう。そこでまずは、新運営陣の顔合わせも兼ねて渋谷で対面のブートストラップミーティングを開くことになった。そのときは僕も新運営の一人として参加していた。

そのミーティングの席で僕はこんな発言をしたのを覚えている。

「そもそもShibuya.lispが何を目的として存在するのかを考えなくちゃいけないんじゃないですか」

単にイベントを開催するにしても、なぜ、というのが明確でなければいずれまた目的を見失う。Shibuya.lispは何かの手段であって、目的ではないんじゃないか、と。

僕のその言葉に一同黙り込んだ。さあ、Shibuya.lispをやる目的とは何だろうか──。

そのとき前運営の立場として参加していた佐野さんが言ったことは、図らずも新しい運営方針を決定付けたものかもしれない。

──「理由はそのコミュニティに集まった人々で作ればいいことで、我々はただその箱を用意すればいいんじゃないかな。だとすれば、『続ける』ということも十分目的になるよ」

そうして、今はTakehiko Nawataさん、Katsunori Kanda (potix2) さん、κeenさんを中心に「Lisp Meetup」が二年半の間、毎月続いている。東京のLispコミュニティは彼らに支えられている。

ELS 2015 @ London, UK

話は変わって、今年の四月にロンドンで「ELS (European Lisp Symposium)」が二日間に渡って開催された。僕は登壇者の一人として初参加、佐野さんは常連参加者の一人として日本から参加した。

ELSはヨーロッパのLisp方言全般のコミュニティだ。一年に一度、大学の講堂やホテルの一室を借りてイベントを開催し、ヨーロッパのさまざまな国から人々が集まる。共通言語は英語だ。

世界規模のイベントと言えば、数年置き開催の「ILC (International Lisp Conference)」というものもある。こちらは北米での開催が多いが、「International」と冠していることからも分かる通り、特に開催大陸が決まったものではない。二〇〇七年はケンブリッジで、二〇一二年には京都でも開催された。

日本からの参加者として見ればどちらも遠い「海外カンファレンス」ではあるけれど、ヨーロッパのコミュニティはILCとは参加者の顔ぶれや雰囲気は異なる。ELSはILCよりも若い参加者が多く、発表もアカデミックなものより実務寄りのものが目立つ。参加者もELSのほうがいくらか多いように見えるが、これはチケット代やビザの取得のしやすさの違いもあるかもしれない。

余談だが、以前は「ECLM (European Common Lisp Meeting)」というCommon Lisp限定のヨーロッパコミュニティもあった。しかし、種々の事情によりここ二年開催されなくなっており、こちらのイベントには僕は一度も参加したことはない。運営を担っていた人が抜けたこともあって、今後の開催も期待はできない。

海外の技術イベントに参加するときに興味深く思うのは、トークの間にある「休憩 (Coffee Break)」だ。二時間置きに三十分の休憩があるという具合で、その時間は皆席を立って思い思いの人と話をする。廊下に出るとコーヒーポットやクッキーが並ぶ。この休憩は文字通り休憩という意味もあるが、交流という意味が強い。登壇者に聞きたいことがある場合はこのタイミングでつかまえる。

https://twitter.com/meymao/status/590459858199130112/photo/1

一日目の最初はQuicklispの作者として知られる「Zach Beane」のKeynoteスピーチで始まる。「Quicklisp: On Beyond Beta」というタイトルで、Quicklispの概要と、プロジェクトのこれからについての話だった。

そのトークの中で意外にも彼は日本のコミュニティについて言及した。

日本語圏のCommon Lispコミュニティは本当に盛況のようで、Clack、qlot、fast-http、optimaなど多くの素晴らしいプロジェクトが見られる。 There also seems to be a real boom in the Japanese-speaking Common Lisp community, and I see some of the effects with great projects like Clack, qlot, fast-http, optima, and many others.

── els-london-2015/script.txt

敢えて彼が特別に「日本」について言及したのは、北米に住む彼にとっても、またおそらくヨーロッパから集まった聴衆にとっても、「日本」という国の人々の活動が意外で馴染みのない場所からのコントリビューションだと見えるからかもしれない。

その後の休憩で、佐野さんと共に、Zachと話す機会を得た。と言っても、会話はほとんど佐野さんに任せて、僕は隣に立っていただけなのだけど。

話は日本のCommon Lispコミュニティについてだ。彼は自身のトークで日本のコミュニティは「盛況」だと言及した。ヨーロッパに招待スピーカーとして登壇するCommon Lisperの彼にとって日本のコミュニティはどのように見えているのか。

──日本語が読めないからよくは分からない。ただ、日本人が作ったCommon Lispライブラリを多く見るから。

Tokyoという場所

日本のCommon Lispコミュニティについて考えると、Common Lispプロダクトを作っている日本人の多くは東京近郊に集中しており、Lisp Meetupで作者本人と出会うことも多い。これは東京に人口や企業の多くが集中しているという日本の地理的事情が無関係ではないだろう。

数年前に京都に住んでいたときに「Kyoto.lisp」というコミュニティを立ち上げようとした。しかし、京都の場合は近郊に人材が足りなさすぎた。初回は良かったが、二回目からはぐんと参加者の数も減った。最後には参加者も発表者も、兵庫や愛知、東京からの参加者を入れてようやく一〇人足らずという有り様だった。あるときその数少ない参加者の大学生から、東京の企業に就職が決まったので四月から参加できません、と聞いたときには東京という土地の引力に眩暈がしたものだ。その後コミュニティは運営に携われる人も見つけられず、数度のイベントを開いたきり続かずに終わってしまった。

GitHubで開発し、メールやTwitterでやり取りができるとはいえ、実際に会って話すことによるメリットはまだ確実にある。お互いに情報を交換し、問題意識を共有し、家に帰って形にする。このサイクルが東京のコミュニティではうまく回り、結果として海外カンファレンスで言及されるほどの存在感を得ているのだと思う。

僕は東京を住みやすい街ではないと思うけれど、人に会うということに関してはこの街ほど魅力的な場所はない。コミュニティの存在に感謝しつつ、今日も一人プログラムを書く。


この記事の下書きを読んで意見をくれた友人のMasatoshi Sanoと妻の@meymaoに感謝します。

訳本「ヘルシープログラマ」を読む

$
0
0

以前、「The Healthy Programmer」を読んだ話を書きました。この夏にその邦訳の「ヘルシープログラマ」が出版され、僕のブログ記事を見ていただいた訳者の玉川竜司さんに献本いただいたので、今もう一度日本語で読み返しています。

f:id:nitro_idiot:20150802204203j:plain:w320

内容としては、普段座りっぱなしのプログラマ向けに健康を考えましょう、という主旨の本です。

プログラマは生産性を上げることが仕事の一部なので、普段から仕事の障害と思うものに対してセンシティブな方だと思います。

ずっとイスに座ってプログラム書いてると腰が痛くなって生産性が下がる。そのとき腰の苦痛を解消するために10万のイスを買ったりとか対症療法的な解決をしてしまいがちです。けど、そういう手段には当然ながら限界がありますよね。

かと言って今度は漠然と、運動しよう!とかいってフルマラソン走ったりする人もいるけど、それで逆に体を壊しても意味がないです。

そこでヘルシープログラマでは、もっと長期的な視点で無理なく健康を維持することで生産性を落ちないようにしようという提案をしています。特に、あまり「運動」に含まれそうにない「散歩」が生産性の維持に与える効果を説明してとてもおすすめしています。

と言っても、振り返ってみて実際に自分の生活に活かせているかというと難しい…。

f:id:nitro_idiot:20150730210703j:plain:w360

活かせている点は、以前のブログ記事を書いたときにエアロバイクを買って机の隣に設置したので、ちょっとしたスキマ時間に乗ったりしています。git pushしてTravis CIが回ってるのを待つ間に画面見ながら乗ってみたりとか。

一方で全く活かせてないところは、家の外に出る機会がほとんど無くなっていることです。それどころか、集中力を持続させるために部屋の移動すら少なくしようと、机の周りで何でも済ませられるようにしてみたり。最近はお茶を汲むためのインタラプションを少しでも軽減するために電気ポットを移動したり、安易に対症療法的な解決をしてしまっています。もっと歩いたほうが血の巡りも良くなって頭の働きも良くなるかもしれないのに。

引越しをしてから、以前は良くしていた散歩も全然しなくなっています。家の環境を良くしすぎなのと、家が大通り沿いであんまり外に出たくないなーっていう心理的な障壁が問題な気がしています。

本を頂いたおかげで良い振り返りの機会を得られたと思います。こういうとき、「ヘルシープログラマ」自体が全然説教臭くないので、変にひねくれずに素直にまた改善しようという気持ちになれるのも良いですね。

近くにいくつか公園もあることだし、これを機会にせめて一日20分程度の散歩を日常に取り入れたいものです。

ヘルシープログラマ ―プログラミングを楽しく続けるための健康Hack

ヘルシープログラマ ―プログラミングを楽しく続けるための健康Hack

Roswell時代のCommon LispのWebアプリケーション運用

$
0
0

最近Quickdocs.orgフルスクラッチしました (2回目)。

今回のメインは裏側の月次バッチ処理でしたが、Webアプリ部分も多少変更をしました。特に運用方法が、Roswellを全面的に使うことで大きく変わりました。

Common LispのWebアプリ開発では、未だにこのブログの以下のエントリが参照されてるっぽいですが内容もかなり古くなっています。なのでこの機会に現代に合わせてアップデートしておこうと思います。

Roswell

何はともあれRoswellが必要です。

Roswellの紹介記事は以前書きました。

RoswellはCommon Lispスクリプトを簡単に実行できる機能があると共に、その配布も簡単にしています。

ros install <ライブラリ名>を実行すると、ライブラリのroswell/ディレクトリ以下のスクリプト~/.roswell/bin以下にコピーして利用可能にしてくれます。

使うライブラリ

QuickdocsではWebフレームワークにCaveman2を使っています。

Caveman2はClackに対応していてDBライブラリとの連携もある軽量なWebフレームワークです。

合わせてDBアクセスはdatafly、テンプレートエンジンはDjulaを使います。どちらもCaveman2のデフォルトです。

アプリケーション起動

開発時はREPLで (quickdocs-server:start)を実行すればHTTPサーバが起動しますが、デプロイすることを考えるとシェルから実行できる必要があります。

Clackはシェルコマンドの「clackup」を提供しているのでRoswell経由でインストールします。

$ ros install clack

Webアプリのプロジェクトルートにapp.lispというファイルがあるので、それをclackupコマンドに渡せばHTTPサーバが起動します。

$ clackup app.lisp
$ clackup --server :woo --port 38080 --debug nil app.lisp

ちなみに以前のQuickdocsはFastCGIを使っていましたが、今はWooで動いています。

ライブラリのバージョン固定

Webアプリケーションを長く運用していると、最新のライブラリではいつの間にか動かなくなっている、というようなことがあります。うまく動き続けている間は問題がありませんが、サーバの追加や移転をしようとしたりするときに困ります。

また、他の誰かがアプリケーションを動かすときに、自分と同じライブラリバージョンを使わないと挙動に齟齬が生じます。

Qlotを使えば、使うライブラリのバージョンを固定できるのでこれらの問題は解決します。clackupと同様、Roswell経由でqlotコマンドをインストールします。

$ ros install qlot

プロジェクトルートにqlfileを作って、qlot installをするとプロジェクトローカルにQuicklispがインストールされ、qlfile.lockができます。バージョンの固定にはこのqlfile.lockが必要なので、qlfileと合わせてコミットしておきます。

プロジェクトローカルのQuicklispを使うにはqlot execします。

$ qlot exec clackup app.lisp --debug nil --server :woo --port 38080

ホットデプロイ

デプロイ時に既存のプロセスを殺して新しいプロセスを立ち上げると、どうしてもサービスのダウンタイムが発生します。

これを防ぐためにServer::Starterを使ってclackupを実行します。これは新しいプロセスをforkしてHTTPサーバを立ち上げるのでportの競合なくファイルディスクリプタを新旧プロセスで共有し、新プロセスが正常に立ち上がったら旧プロセスを殺します。

clackupはServer::Starterに対応しているので使うのに特に難しいことはありません。

$ start_server --port 38080 -- qlot exec clackup app.lisp --debug nil --server :woo

死活監視

アプリケーションプロセスが、何らかの要因でいつの間にか落ちてサービス停止するのを防ぐためにプロセスの死活監視を行います。これにはSupervisorを使います。

リバースプロキシ

アプリケーションサーバの前段にNginxをリバースプロキシとして置きます。ここではアクセスログの出力や、エラー発生時にエラーページを返したり、その他静的ファイルの配信を行います。

デプロイ

デプロイ時に毎回SSHしてgit pullして再起動するのは面倒なので、ローカルから簡単にデプロイできるようにします。これにはFabricを使います。

こんな感じのfabfile.pyを書いておけば以下のようにデプロイができます。

$ fab server deploy

デプロイ時には以下のことをしています。

  • git pullする
  • qlot installする
  • supervisord からプロセスを再起動する

supervisorctl restartするとSupervisorがServer::StarterにSIGTERMを送って、Server::Starterが新しいプロセスを立ち上げます。立ち上がったら、Server::Starterがclackupにシグナルを送り、最終的にWooがリクエストを捌いてから終了します。

ただし、このfabfile.pyには実は問題があります。

git pullした時点でHTMLテンプレートや静的ファイルは更新されて再起動なしで配信されてしまうので、走っているプロセスとの不整合が起きます。

これを防ぐにはデプロイ時に毎回別ディレクトリにgit cloneして、サーバ起動前にすり替えるみたいなことが必要なんですが、Fabricはそういう気の利いたことをしてくれないので自分でPythonを書く必要があって面倒なので今のところ放置しています。

サービス監視

サービス監視にMackerelを使っています。

ただ、Quickdocsはまだそれほどトラフィックもないので、DBもアプリもバッチもリバースプロキシも1台のサーバに共存しているので、全く活かせている気がしませんが…。

f:id:nitro_idiot:20150804154702p:plain

まとめ

全体的にCommon Lispもこなれてきたなーと思います (毎回言ってる)。Roswellのおかげで簡単にスクリプトが書けるようになったのでServer::StarterやSupervisorなど、他のツールとの組み合わせが簡単になっています。

心残りはFabricかなー。もうちょっと何とかなりそうだけどPythonは書きたくないし。Common LispのデプロイツールがあればリモートのSwankサーバとの連携とかもできそう。

今回紹介したQuickdocsのWebアプリ部分はGitHubに公開されています。

Ansibleのplaybookはこちらです。

Lisp Meetup #31 で「Dexador Rises」という発表をしました

$
0
0

今月の Lisp Meetup #31で、拙作のHTTPクライアントライブラリの「Dexador」の話をしてきました。

事実上Drakmaの一人勝ち市場なんだけど、Drakmaって割とハマりがちだよね、っていう話に賛同を得られました。

Dexadorは現在v1.0.0リリースに向けて安定化を再優先に開発しています。

他の発表

UFO

@ta2gchさんからUFOの発表がありました。

UFOはRoswellスクリプトをインストールするためのRoswellスクリプトです。Web上に公開されたRoswellスクリプトを簡単にインストールできる「go get」相当の機能を提供します。書いた便利Roswellスクリプトをgistなどに公開すれば、ufo gist://fukamachi/clhs.rosなどでインストールすることが可能です。

本人がezoeコマンドを作ったときに、配布に困ったという体験から生まれたプロダクトのようです。いずれQuicklispに登録しよう、という話もしていたので、そうなればUFO自身のインストールも簡単になりそうですね。

あとclfreaks聞いてくれてありがとうございます!

Inquisitor

ぐれー (@sin_clav) さんのCommon Lisp文字コード・改行コード判定ライブラリ「Inquisitor」の発表がありました。

文字コード判定の処理や、処理系毎のexternal-formatの抽象化など、割と泥臭くて闇が深いということがわかりました。

DexadorでContent-Typeがtext/*だけどcharsetが指定されていないときに、現状はbabel:*default-character-encoding*を使ってエンコードするんだけど、Inquisitorを使えばある程度賢く判定できるかなー、と思ったりしました。ただ言語圏が取れないんだよなぁ。

あと速いの?とか気になったりしたけど、そういう老害的な発言はやめようという良心が勝ちました。

lem

佐野 (@snmsts)さんから、Common Lispで書かれたEmacsライクなエディタ「lem」の発表がありました。デモが中心なのでスライドはありません。

自分のプロダクトではないのに紹介する経緯としては、Emacs Lispよりマシな言語でカスタマイズしたいよね、っていうモチベーションだそうです。

TwitterのTLでは早速lemを試してみている人びとが観測されました。

まだCでSEGV出るより簡単に落とせるレベルとか言っていて、普段の開発で使うには怖いなーという感じだけど、Common Lispで書かれているし行数もまだ5000行程度なのでなんとかなりそう。Common LispシンタックスハイライトとSLIMEとEvilがあれば移れるかなぁという感じ。

lem自身がCommon Lispで書かれているので、エディタのカスタマイズ言語としてもフルのCommon Lispが使えます。デモでは実際にエディタ上でClackによるWebサーバ起動もしていました。この点はxyzzyと違ってまったく癖なく使えそうです。cl-ppcreとかも普通に動くってことだし、リーダマクロもたぶん動くよね。

作者ご本人の紹介記事はこちらです。

lizx.hatenablog.com

Clake

takagi (@kamonama) さんの、Common LispGNU makeライクなプログラム「Clake」の発表がありました。

主にRubyのRakeの置き換えを念頭に置いて開発しているようです。コマンドラインでの実行部分にはRoswellスクリプトが使われています。

発表後にclakeって名前がclackにtypoしがちなんだけど、っていうフィードバックをしました。「cla」とかするとclakeじゃなくてclackupが補完されたりしてちょっと使い勝手が悪い。早速Issueにて良い名前はないか募集がされています。案のある方はコメントすると良いのではないでしょうか。

github.com

Roswellのモメンタム

発表のうちUFOとClakeはRoswellスクリプトによる実装であり、他の発表でも何かしらの形でRoswellへの言及がありました (CIで使ってるよ、とか)。もはやRoswell Meetupと言っても過言ではない。この調子でRoswellがどんどん浸透していくと良いですね。

ISUCON5オンライン予選にclfreaksとして参加しました

$
0
0

9/27(日)に開催されたISUCON5のオンライン予選に参加しました。

僕はアプリケーション側の改善、他の二人はインフラ寄りの対応をするように事前に役割分担をしていました。

“ISUCON”とは

ISUCONは「Iikanjini Speed Up Contest」の略で、LINE株式会社 (昔はLivedoor) が主催する、アプリケーションやインフラのパフォーマンスチューニングを行ってそのスコアを競うイベントです。2〜3人のチームを作って参加します。

優勝賞金100万円!今年もやります ISUCON5 開催と日程のお知らせ #isucon : ISUCON公式Blog

この週末の2日間にオンライン予選が行われました。

チームビルディング

ISUCONというイベント自体は知っていたのですが、どうも自分には縁遠いものだと思っていました。まさか参加することになろうとは。

というのも、ISUCONではチューニング対象の環境 (アプリケーション)が出題者側から与えられます。その実装がPerlRubyPython、Goなどで、始めに好きな実装を選びます。

出題者から提供される参照実装に「Common Lisp」はありません。

僕は普段からCommon Lispアプリケーションしか書いていないし、インフラのチューニングも業務でやるようなこともないので、出場したところでなぁと思っていたわけです。

そんな時、κeenさんに「ISUCON出ませんか」と誘われました。

でもCommon Lispは無いんでしょう、と言うと、「ISUCONはベンチマークスコアが良ければアプリケーションにいくらでも手を入れていいという特徴があるので、いっそCommon Lispで再実装してしまいましょう」、と豪胆なことを言います。

「そんな斜め上の戦略でうまくいくのか」という無粋な話もしたのですが、インフラに合わせてアプリケーションはダイナミックに変更する必要があり、いずれにしても大きく変更するなら同じだろうというのです。実際、前回の予選ではC++でアプリケーションを書き直すことで本戦出場したチームもいたそうです。

そう言われると確かに面白そうだ、ということで、誘われるままにκeenさん、Rudolph Millerさんと3人で出ることになりました。

チーム名は「clfreaks」です。そのままですね。

前日まで

とりあえず、高速なCommon LispのWebアプリケーションを目指すならWooを使うことになりそうなのは目に見えています。

f:id:nitro_idiot:20150928044620p:plain

かねてからTODOリストにあったWooのUNIXドメインソケット対応を急遽実装することに。どう考えてもISUCONの前日にすることではない。実装自体は大体2時間くらいで終わった。

あとはRedisを使う場合に備えてcl-redisに使い方確認とか。

過去問を見るとセッションを使うものが出ることが多そうだったのでLackのセッションミドルウェアのパフォーマンスも改善しました。不要の場合はSet-Cookieヘッダを送らないとか。本番では結局使わなかったけど。

それから夜に時間があったので、Common Lispでの軽量なWebアプリケーションの雛形を作りました。ningleかCaveman2でもよかったんだけど、性能上の不安要素はできるだけ取り除きたいという理由で、Clackを生で使ってMy Wayでルーティングすることにしました。

qlot exec clackup --server :woo --listen /tmp/woo.sock app.lispでアプリケーションが起動することを確認して当日に備えました。

当日

"オンライン"予選なんだけど、LINEさんの好意で渋谷のLINEカフェも利用可能だったので全員で9:30に渋谷のヒカリエに集合しました。

10:00にGCEのイメージが配布され、他の二人はインフラ構成、僕はアプリケーションコードを読んでいました。

かねてからの予定では、最初の2時間ほどは作戦会議だったのですが、11:00頃から、とっととCommon Lispで実装始めちゃったほうがいいかもね、という話になって、Ruby実装を参考にCommon Lispへの移植を始めました。その間に他の二人はRuby実装をデプロイして、MySQLの改善などをしていました。

使ったもの

今回のアプリケーションはERBのテンプレートファイルが多く、静的ファイルにもしづらかったのでテンプレートエンジンとしてCL-EMBを使いました。MySQLへのアクセスはCL-DBIです。

参考実装はセッションミドルウェアを使っていましたが、単にuser_idをクライアント側に保持させたいだけっぽいのでSet-Cookieヘッダで対応しました。

あとは静的ファイルはすべてNginxで配信するのでStaticミドルウェアも無効に。Lackミドルウェアで使ったのは結局Backtraceだけでした。

無限に時間がかかる

そこから割とガツガツ実装したつもりなんですが、時間はいくらでも過ぎていく。

当初はN+1クエリの改善 (is_friend?get_user) とかも書き換え中にやろうとしていたんだけど、考えている時間ももったいないので、とりあえず動かせるところまで持っていくことを優先。ローカルのDBにデータが無いのでローカルで動かすことはできない。フルスクラッチする場合はもっと早めにmysqldumpしておくべきという謎の知見を得る。

テンプレートなんてちょろっとCL-EMB流に書き換えるだけだろ、と思ったら大間違いで、テンプレート内で普通にget_user呼んだりしていて泡吹きそうだった。db.xqueryとかテンプレート内で呼ぶんじゃない…。

デプロイ

f:id:nitro_idiot:20150928051017p:plain

κeenさんが前日にCapfileを用意してくれて、Capistranoでデプロイできるようにしてくれた。

f:id:nitro_idiot:20150928051151p:plain

シェル芸人の暴挙は阻止しました。

チャットのログを見ると、だいたい16:30くらいに最初のバージョンをデプロイしたようです。残り1時間半。

バグを踏む

ただ、デプロイしてつもりがNginxが502 Bad Gatewayを返してきます。WooのUNIXドメインソケット対応のバグっぽい。

そこからWooのデバッグを始めて、その場で修正。どう考えてもISUCON中にすることではない。

あとは、RoswellでWooを起動するとC-cで終了できないとか結構不便だった。原因は未確認。

clackupコマンドに--debug nilを指定すると、:debugに文字列で"nil"が渡っていて真になるとかいう渋いバグも踏んだ。あとで直す。

デプロイが遅い

ISUCONみたいな時間制限のある競技だと、デプロイが遅いと試行回数が減ってしまいます。

Common Lispのデプロイが遅かった原因は、Capistranoだとホットデプロイのために毎回別ディレクトリにgit cloneしてqlot installを走らせるんだけど、その度にQuicklispとライブラリのインストールが走り、さらにコードのコンパイルが行われる。御存知の通りSBCLコンパイルは遅いです。競技中に「あいあんくらっど〜〜〜〜〜」って叫んでいたのはうちのチームだけだと思う。

対応としてリポジトリquicklisp/ディレクトリを含めてしまう、ということもしたけどあまり改善しませんでした。今後の課題です。

歓声

デプロイは終わったんだけど、結局アプリケーション側のバグでログインができない状態がしばらく続きました。

17:45になってようやくログインが成功し、ホーム画面が表示され、思わず「お〜〜!!!」と歓声。もはやCommon Lispで書き換えたものが時間内に動いたってだけでうれしい。

ちなみに上位チームが20000とかスコアを叩き出している中、弊チームのベンチマークスコアは5でFAILでした。

振り返り

手際の問題とかいろいろあったと思うけど、今回の出題ではアプリケーションコードのボリュームが結構あって、Common Lispで再実装するという選択をした時点で予選通過の見込みは無かったように思います。かと言って、このチームでCommon Lisp捨てて中途半端な成績を残しても悔いは残るってんで、まあ今回は仕方なかったね、っていう話をしました。

結果、Common Lispの性能上の優位性を示すことはできませんでした。

たとえば、今回は静的ファイルへのアクセスがほとんど来なかったので、思い切ってNginxを切ってWooをフロントにしてみるようなチャレンジができなかった。LackやCL-DBIのパフォーマンスがどの程度出るか、とかも踏み込めなかったのは心残りです。

いくらか見つかったCommon Lispでの問題は今後の課題にします。

ISUCON 6?

なんにせよ今回の参加は僕個人にとっては良い経験となりました。LINEの運営者陣、Treasure Dataの出題陣、あと誘ってくれたチームメンバーに感謝します。

来年もISUCONがあるとしたら、出場するよりもむしろCommon Lispのアプリケーション実装を作る出題側の手伝いをしたいと思いました。競技中にアプリケーションを書き換える時間を無くせばCommon Lispでももっと踏み込んだ性能比較ができますしね。

参考

チームメンバーのκeenさんもエントリを書いています。

語らるるべき日本のCommon Lisper達

$
0
0

Lispのエッセイのようなものを継続的にブログに載せていこうとしたのはいいのだが、立て続けに2つ載せたきりなかなか続かない。これはその3つ目のものである。

今回は「人」に焦点をあてて、Common Lispコミュニティで現状活発に活動している人を紹介する。挙げてみると、どうしてもそれなりに親交のある人に偏っている。またいずれ時をおいて第二弾でも書くかもしれない。

佐野匡俊

佐野さんは僕がLispを始めた頃からの知り合いである。最初に会って話をしたのは2010年に米国のリノというカジノ街で開催されたInternational Lisp Conferenceで、その後も国内外のカンファレンスでよく顔を合わせた。

今回紹介する中では年長で、100kgを超える縦にも横にも大きな体つきをしている。「待ち合わせは佐野さん前」と言われるくらい、人混みの中であろうと遠くから見てすぐ分かる。

だが、兄貴分という柄ではない。自信のなさそうなぼんやりした話し方。積極的入社Common Lispの良さを広めていくわけでもない。自分はCommon Lispのことが好きだけれど周りはどう思うか知らない、という態度で佇んでいる。どうも、みんなで公園で遊んでいたはずが、いつの間にか自分だけがそのまま取り残されてしまった子供のような様子である。

かと言って自分の主義主張が無いわけではなさそうだ。

2010年の10月、当時の僕の雇い主が主催の社外勉強会で「Lisp脳」というテーマでやることになった。佐野さんも何か話してもらえませんかね、と講演を打診すると、即答はしづらいと言いながらも引き受けてくれた。

佐野さんが登壇し、Common Lispの魅力を語る下りでこんな話をしていたのを覚えている。

Common Lispには (他の言語と比して) まだまだ足りない部分が多いです。新雪を踏みたい人には、まだいくらでもあります。ぜひ一緒にやりましょう。

彼はよくこのような文学的な表現をする。

当の本人はそんな話をしたことも覚えていまい。が、これを聞いた僕が、その後ウェブ周辺の新雪を踏み荒らしていったというのはご存知の通りである。

自分のブログは持っていないのでウェブで自分を語るようなことは無いが、話せば広い視野と気の長い展望を持っている面白い人物である。

実践Common Lispの訳者であることでこれまでも多少知られていたが、最近はRoswellの作者というほうが有名になってきている。

Rudolph Miller

Rudolph MillerはCommon Lisp界の若手ホープである。コミュニティに参加する前から独学でCommon Lispを学び、僕が会ったときには一人前のCommon Lisperだった。

趣味は何かと聞けば「Common Lisp」と答える。事実、平日も週末も関係なく年がら年中コードを書いている。出かけるときはいつもMacBookHHKBを持ち歩く。彼のことだから、おそらく僕が死んで葬式に現れたとしても参列席でMacBook開いてプログラムを書いているだろう。

一時彼とはサムライトという会社で同僚となったが、彼の生産性には目を見張る。

僕が入社するまでRailsで動いていたアプリケーションをたった一人、しかもほんの一ヶ月でCommon Lispにすっかり書き直してしまった。その後続けてNode.jsの広告配信サーバもCommon Lispで書き直し、上々のパフォーマンスを出している。

コードを書くだけでなく読む量もどうやら凄まじい。「この週末に深町さんのSxQLのコードを読んでみたのだけれど、面白い設計ですね」とか、「Qlotでハマったので読んでみたんですけど、想像よりも大変なことをしていますね」などと感想をくれたことも一度や二度ではない。その度に、彼の技術は魔法のようなものではなくこういう影の活動の積み重ねで裏打ちされているのだな、と感心したものである。

また、彼は僕に高速なHTTPサーバを書かせるきっかけを作った人物でもある。

サムライトに入社する前の話だ。ある日、僕がTwitterでNode.jsの話をしていた。「Node.jsか。速い速いって言うけど遅いじゃねぇか。Common Lispに移植したら、大して努力もしないで35倍も速くなった」

するとRudolph Millerが「HTTPサーバはどうです」と言ってきた。「さあ、計測したことはないけど」Common LispのイベントドリブンなHTTPサーバといえば当時はWookieしかなかった。これとNode.jsのhttpモジュールのベンチマークを取ってみると、なんとCommon Lispが2倍も遅かった。

この屈辱的とも言える事実を見て、僕はWookieや、そのHTTPパーサ「http-parse」にパッチを何度か送ることとなった。その度にいくらかパフォーマンスの改善は見られたが、Node.jsほどではない。そのうちに、こんなんじゃやってられん、ということで自前で書き直すことにした。それが「fast-http」や「Woo」である。

それから数ヶ月Wooの改善を続け、Node.jsと同程度には速い、というくらいになった頃。これでいいかねぇと言うと、Rudolphが「高速な言語のCommon Lispがそれでいいんですか」とニヤニヤ言う。言うねぇ、生意気なやつだ、それじゃあ行けるところまでやってやるかーー。

Wooのバックエンドをlibeventからlibevに置き換え、もはや完全にWookieとは別物になった。今やWooはNode.jsの2倍速い。彼は書くコードもそうだが、言うこともなかなか鋭く煽り方も一流である。

そんな彼も、先日サムライトを退職してCommon Lispを使わない企業に転職した。彼はそうとは言わないが、今後はCommon Lispを書く機会も然程もなかろう。残念なことである。

κeen

粗忽長屋」という落語がある。

浅草の観音に参りにきた八五郎は道端に人だかりが出来ているのを見つける。どうやら昨晩から行き倒れの死骸の身元がわからないので知っている人物を探しているらしい。八五郎は死人の顔を見るなり、これは隣に住んでる熊五郎だ、と言う。今朝会ったのだからそんなわけがないのだが、あいつ自分が死んだことに気づいてねーんだ、と言って長屋に戻って熊五郎を説得する。最初は否定していた熊五郎もいろいろ言われるうちに自分は死んだんだと納得してしまうという滑稽噺である。

粗忽長屋立川談志- YouTube

咄家の立川談志は、この落語を「主観長屋」として少し脚色を加えて演じた。

「“たまには(ひげ)()たれ” つってるじゃねえか」
「髭なんぞはどうでもいいんだい」
「人間てえのは鏡見んだろ。鏡ィ見りゃ、自分の顔ってのが判るじゃねえか。俺なんぞは、(まい)(にち)顔洗って、歯ァ磨いて、髭なんぞ剃るから、自分で自分が判る。だから、街で歩いてて、あ、俺だなってすぐ判る。お前は自分のことが判んない。俺はお前が判って、俺が判って、両方判ってる。俺が“お前だ” つってンだから、間違いねえだろう」
 こいつは“粗忽”ではない。あまりに主観が強いと、人間の生死までも判らなくなってしまうという、物凄いテーマを持った落語なのだ。

談志 最後の根多帳 (談志最後の三部作 第二弾)より

κeenさんにも、この八五郎のようなところがある。

非常に思い込みが強く、一度そうだと思ったら他の全員が違うと言ってもなかなか自分の意見を曲げない。不具合報告を彼からもらっても、よくよく聞けばκeenさんの勘違いだったりする。なのに語気は強いのだから後から思い返すと笑ってしまう。どうも彼は「主観」が強いらしい。

κeenさんがコードを書くときの勢いには目を見張るものがある。たとえば、彼のプロダクトの一つである「CIM」は、次のLisp Meetupが一週間後に迫っているという頃に書き始めて、一時はどうなるものかと思っていたが当日には非常に多機能なものを仕上げてきた。

しかし、その後目立った機能追加は無く、不具合もなかなか直らない。結局CIMは後発のRoswellに取って代わられてしまった。彼はどうも飽きっぽい性格のようで、作るときは並ならぬパフォーマンスを発揮するが、ある程度形になると手をかけるのをやめてしまう。結果中途半端なものがGitHubリポジトリに並ぶ。勿体無いものである。

彼はShibuya.lispの現行運営の一人でもある。積極的に月次のLisp Meetupの開催を助けるだけでなく、発表者が集まらないときは率先してLTをする。たとえ彼が仕事や私生活で忙しそうにしているときでも何かしら興味深い話をまとめてくる。彼が粗忽さや飽きっぽいという欠点を抱えながらもコミュニティで愛される立場にいるのも、彼のこのサービス精神の旺盛さから来るのかもしれない。

g000001

g000001さんを挙げなければ日本のLispコミュニティを言い表せないように思う。

とはいえ親交があるわけではない。昔にTwitterやブログで僕が生意気なことを言って怒らせたという経緯もある。ただ、僕に限らず彼との親交を持ち続けている人は周りにいない。古くからこのコミュニティにいる人は「あぁ千葉さんか」などと知人のように呼ぶが、じゃあ知っているのかと思いきや、聞いてみても大して知っているわけでもない。おにぎりのアイコンなので「おにぎりの人」などと呼ばれている。

昔、橘右近という寄席文字の職人がいた。日本テレビの人気テレビ番組「笑点」の舞台の後ろには、彼の書いた寄席文字が額で飾られている。その彼には寄席文字だけでなく、収集家としての趣味もあったらしい。

右近さんは、寄席の古き文献を集める趣味があって、新聞、雑誌の切り抜きはもとより、「ビラ字」や「鳴り物」で稼いだ金を、惜しげもなく使い、「昔のビラ」や「楽屋帳」「本」「写真」を集めてくる。その数は大変なもので、自分達の歴史をほとんど大切にしない寄席や、咄家の中で、貴重な存在になっている。

談志人生全集〈第1巻〉生意気ざかりより

g000001さんはLispコミュニティの橘右近のような存在である。方言に関係なくLispの古い文献・プログラム・MLのメールなどを集めている考古学者だ。Lispはそれこそ歴史がある言語なのでその情報量は膨大であるはずで、その一部は彼のブログで垣間見ることができる。

現代のコミュニティにおいても、Reddit/r/lisp_jaで日本語のLisp情報を活発に収集・共有を行っている。有名なブログだけでなく初心者がちょっと試してみたというような記事まで拾ってくるのだから、彼のアンテナの広さには感嘆させられる。

その他にも逆引きCommon Lispを運用していたり、Stack OverFlowの日本語版Common Lispの質問に積極的に回答したりなど、初心者向けのサポートも熱心である。

Shibuya.lispの初期運営を降りてからは人の集まる場所には滅多に顔を出さないが、ブログでは活発に情報発信を行っている。

HubotスクリプトをCommon Lispで書く

$
0
0

f:id:nitro_idiot:20151225001557p:plain

いい加減ChatOpsにも手を付けたいなぁ、と思って、試しに家庭内SlackにHubotを導入してみました。

HubotはGitHub社製のチャットボットフレームワークです。CoffeeScriptで書かれていてNode.jsで動きます。挙動を追加するにはCoffeeScriptスクリプトを書きます。

これを利用して、チャットというインターフェイスを使って様々な日常タスクを処理させることができます。最近の流行りでは、hubot deployなどと唱えるとチャットからサーバのデプロイをしたりできるようです。

今年もChatOps Advent Calendarでチャットボットを使ったテクニックが投稿されているようです。

さて、導入したのはいいのですが、CoffeeScriptを書くのがどうにもダルいJavaScriptも受け付けるらしいけど、やっぱりさくっと書ける言語のほうがいい。つまりCommon Lispがいい。

かと言ってCommon Lispで一からボットフレームワーク作る労力は割けない。どうにかHubotを使ってできないかやってみることにしました。

ヘビーにRoswellに依存しているのでRoswellを知らない方はあらかじめこちらを参照してください。

サブプロセスでRoswellスクリプトを呼ぶ

まず考えたのが、Hubotスクリプトでサブプロセスを立ち上げてRoswellスクリプトを実行し、その結果をチャットに流す方法です。これならば主な実装をCommon Lispで書くことができます。

ディレクトリ構造
├ scripts/
│   Hubotスクリプト (.coffee, .js) 置き場
├ roswell/
│   Roswellスクリプト (.ros) 置き場
├ bin/
│   実行ファイル。hubotなど
├ Lakefile
├ README.md
├ external-scripts.json
├ hubot-scripts.json
└ package.json

以下のようなHubotスクリプトをscripts/whoami.coffeeに置いて、

module.exports =(robot)->
  robot.respond /who are you\?/i,(msg)->@exec= require('child_process').exec
    command ="sh #{ __dirname }/../roswell/whoami.ros"@exec command,(error, stdout, stderr)->
      msg.send error if error?
      msg.send stdout if stdout?
      msg.send stderr if stderr?

そこから呼び出されるスクリプトをroswell/whoami.rosに書きます。

#|-*- mode:lisp -*-|##|exec ros -Q -- $0 "$@"|#(defun main (&rest argv)(declare(ignorable argv))(formatt"~&I'm fukabot!~%"))

こうすれば “who are you?” と声をかけると roswell/whoami.ros がサブプロセスで実行され、結果の “I’m fukabot!” が返ってきます。

f:id:nitro_idiot:20151224234827p:plain

前準備はサーバにRoswellをインストールすることだけです。手軽ですね。

全部Common Lispで書く

しかし、人間は欲が深い。

上記の方法では、新しくスクリプトを追加するときにCoffeeScriptとRoswellスクリプトの二つを追加しないといけません。これが何とも煩わしい。

特に、どの文言にマッチするかはCoffeeScriptに記述するのに、実装は別のファイルっていうのがあまりイケてない。全部Roswellスクリプトに書きたい。

そこで、少し変わったRoswellスクリプトを書くことで、そこからHubotスクリプトを生成する方式に変更しました。

拙作の hubotify.rosという変換用Roswellスクリプトを使います。これを実行権限をつけてbin/以下にでもダウンロードしておきます。

上述のRoswellスクリプト (roswell/whoami.ros) を以下のように追記します。

#|-*- mode:lisp -*-|##|exec ros -Q -- $0 "$@"|#(defun main (&rest argv)(declare(ignorable argv))(formatt"~&I'm fukabot!~%"))(ql:quickload :parenscript :silent t)(import'(ps:ps ps:@ ps:regex))(defun js-main ()(ps
    ((@ robot respond)(regex "/who are you\\?/i")(lambda(msg)(run-main
        (lambda(error stdout stderr)(whenerror((@ msg send)error))(when stdout
            ((@ msg send) stdout))(when stderr
            ((@ msg send) stderr))))))))

関数js-mainがあるのが特徴です。この関数はJavaScriptコードを文字列で返せば何でも良いです。JavaScriptコードを生成するのにはParenScriptを使っています。

関数run-mainは第一引数にcallback、以降の可変長引数としてRoswellスクリプトへの引数を受け取ります。

最後にこのRoswellスクリプトに対して hubotify.ros を実行します。

$ bin/hubotify.ros roswell/whoami.ros
Wrote '/Users/nitro_idiot/Programs/etc/fukabot/scripts/whoami.js'

これで scripts/whoami.js が生成されるので、そのままデプロイすれば大丈夫です。

ちなみに生成された whoami.js の中身はこのようになっています。

function runMain(callback) {var argv = [];
    for (var i1 = 0; i1 < arguments.length - 1; i1 += 1) {
        argv[i1] = arguments[i1 + 1];
    };
    this.execFile = require('child_process').execFile;
    __PS_MV_REG = {};
    returnthis.execFile(__dirname + '/../' + 'roswell/whoami.ros', argv, new(Object), function (error, stdout, stderr) {
        callback(error, stdout, stderr);
        __PS_MV_REG = {};
        returnnull;
    });
};
module.exports = function(robot) {
robot.respond(/who are you\?/i, function (msg) {return runMain(function (error, stdout, stderr) {if (error) {
            msg.send(error);
        };
        if (stdout) {
            msg.send(stdout);
        };
        return stderr ? msg.send(stderr) : null;
    });
});
};

新しくスクリプトを追加したいときはRoswellスクリプトを追加し、hubotifyすればHubotで使える形になります。

変換のときはLakeのタスクでlake hubotifyのように全てのRoswellスクリプトに対して実行できるようにすれば楽です。

;; Lakefile(task "hubotify"()(dolist(file (uiop:directory-files #P"roswell/"))(sh `("bin/hubotify" ,(namestring file)))))

まとめ

Roswell三昧でした。意外とやってやれないことはないものですね。

ParenScript部分が少し癖がありますが、そこは使っていくうちに共通化してもう少しこなれてくるんじゃないかと思います。


割と本気で家庭用Slack Botを作ってみた

$
0
0

僕は妻と二人暮らしをしています。かつてはLINEを使って普段のやり取りをしていたのですが、一年ほど前からSlackを使い始めました。

Slackの良いところはハッカビリティが高いところです。Google Calendarなど他のサービスと連携することができるし、IFTTTを使って多少凝ったこともできます。

IFTTT時代

IFTTTを使えば天気予報をSlackチャンネルに流せます。

f:id:nitro_idiot:20160113142319p:plain

英語というのは不本意ですが、一応今日の天気はわかります。英語が読めなくてもアイコンを見れば、雨が降りそうな気がするってくらいはわかります。

しかし、しばらく運用しているうちに疑念が。

f:id:nitro_idiot:20160113144739p:plain

天気予報が当たらない。

IFTTTが連携している天気予報は「The Weather Channel」の情報なのですが、これが日本の気象庁の予想と違っていて全然当たらない。

ちなみにiOS8から標準の天気アプリが提供している予報もこの情報のようです。

当たらない天気予報をいつまで見ているのもバカらしい。そこで移行を考えます。

myThings時代

myThingsはYahoo Japanが提供するIFTTTのようなサービスです。IFTTTと違って日本製なので日本語で使えますし、日本ローカルなサービスの対応も手厚いです。

f:id:nitro_idiot:20160113145714p:plain

myThingsはYahoo!天気に対応しているので、ルールを追加するだけでSlackに導入できます。

f:id:nitro_idiot:20160113145100p:plain

Slackの連携に自分のアカウントを使ってしまったため僕が毎日投稿しているように見えるのがかっこ悪いですが、まともな天気予報を知ることができるようになりました。

Hubot時代

しかし人間は欲深い。myThingsを使い始めて程なく不満が出てきます。

「一目で天気がわかるようにアイコンが欲しい」
「降水確率20%って傘必要?不要?」
「URLの展開が幅とりすぎ」

こうなると自分でボットを運用したほうが良さそうです。

カッとなった僕は、おもむろに趣味用に転がしてるさくらVPSにHubotをデプロイし、最強の家庭用Botを作る旅に出ました。

毎朝、天気予報を投稿する

f:id:nitro_idiot:20160113145529p:plain

まずは天気予報の投稿の改善から。Yahoo!天気はAPIが無いので実装が少しばかり複雑です。

APIはありませんが、公式のTwitterアカウント(@Yahoo_weather)が毎日「#東京の天気」というハッシュタグ付きでひと言ツイートをしています。

これが読むのにちょうどいい長さ。TwitterのSearch APIを叩いて「#東京の天気 from:Yahoo_weather」の最新ツイートの本文をSlackに流しました。

これだけでは味気が無いので、Yahoo!天気の東京の天気のページスクリーンショットを撮り、ImageMagickで今日の天気の部分だけ切り出して、切り出した画像をGyazoに投稿してSlackに流しました。

スクリーンショットの撮影にはpython-webkit2pngを使っています。サーバにQtのインストールが必要です。

試行錯誤の結果、今のところ不満はありません。

電車が遅延しているときに報告する

f:id:nitro_idiot:20160113151912p:plain

いざ出かけようというときに利用する予定の電車が止まっていて迂回しないといけない、ということが稀によくあります。

そこで、よく利用する路線の遅延情報をSlackに流すことにしました。

JRの運行情報東京メトロの運行情報スクレイピングして、よく使う路線の遅延情報を得ます。

今のところ遅延しているときには自動で教えてくれるようになっています。遅延が解消されたときには改めて教えてくれます。「fukabot 遅延」と話しかけると遅延しているかどうかに関わらず登録しているすべての路線の情報を教えてくれます。

常に流れていてもうるさいだけなので、平日の通勤時間(8:30〜9:59と18:30〜19:59)と、土日のみ動くようになっています。

宅配便が届く時間を投稿する

f:id:nitro_idiot:20160113172140p:plain

宅配便が届くときには家に誰かがいないといけません。けれど「何日の何時に荷物が届く」というのをいちいち口頭で共有するのは面倒です。そこでSlack Botに自動で報告させるようにすれば忘れることもありません。

クロネコヤマトや佐川急便は、Webでユーザー登録をすると配達予定をメールでお知らせしてくれます。GmailAPIを叩けば配達予定お知らせメールが届いているかはわかるので、それをSlackに投稿するだけです。

Slackの投稿のタイトル部分が配達業者のWebサイトへのリンクになっていて、変更したい場合はすぐにWebサイトから変更できます。

現在、AmazonやSEIYUネットスーパーにも対応しています。どれも事前にメールを送ってくれるので、本文のパース部分以外は同じです。

スーパーのお買い得情報をお知らせする

f:id:nitro_idiot:20160113181048p:plain

最近はネットスーパーを利用し始めましたが、魚や肉は店頭で見て買いたいので最寄りのスーパーも利用します。

我が家では毎夕にシュフモが提供するお買い得情報がSlackに流れます。

チラシのような表示をそのまま活かしたかったのでテキストではなく、スクリーンショットを撮ってImageMagickで切り抜き、Gyazoにアップロードして利用しています。

夫婦の記念日をお知らせする

f:id:nitro_idiot:20160113172956p:plain

普通の機能だけではつまらない。せっかく夫婦で使っているので、夫婦っぽく記念日の情報とか流してみることにしました。

はてなカウンティングでカウントアップを作成し、そのスクリーンショットを撮って切り抜き、Gyazoにアップロードします。

記念日とキリの良い日数のときにお知らせしてくれます。「fukabot 記念日」と言うとすべての記念日情報を教えてくれます。

f:id:nitro_idiot:20160113173258p:plain

適当に作ってみたのですが、今のところ妻の反応が一番良かった機能です。

書籍の情報を教える

f:id:nitro_idiot:20160113165121p:plain

夫婦の間では読んでる本や読みたい本の話をすることが多いです。

「この本買おうと思うけど」みたいな話をするときに、Amazonだといくらか、Kindleで買えるか、図書館で借りられるかを知りたい。そこで、Slackで書籍のタイトルを言うと書籍の情報を表示してくれるようにしました。

まずは楽天ブックスAPIで検索をしてISBNを取ります。これを使ってAmazonにアクセスして書籍や電子書籍の価格、サムネイルなどを取得します。図書館の貸し出し状況の確認にはカーリルAPIを使っています。

「book:本のタイトル」と言うことでも反応するので会話の中に埋め込みやすいです。

f:id:nitro_idiot:20160113171815p:plain

夫婦の読書状況を共有する

f:id:nitro_idiot:20160113174934p:plain

引き続いて本の機能です。夫婦共に日常的に本を読みます。今相手が何の本を読んでいるか、面白いか面白くないか、などの話をよくします。

夫婦二人とも読書メーターを使っているので、読み始めた本や読み終わった本が追加されたときにSlackに流すようにしました。

読書メーターにはAPIが無いのでスクレイピングしています。

まとめ

他にスケジュールの共有やゴミ出しの日のリマインダ、タスク管理などもSlackに連携しています。

紹介した機能は既存のHubotスクリプトを使わずに全てCommon Lispで実装しています。

既存のものを使わないので細かい調整ができるし、試行錯誤しながら夫婦に合わせてカスタマイズができます。

今のところ著しく生活が豊かになった、という実感はないですが、今後も生活の中でできるところは自動化なり何なりしていきたいです。プログラマですからね。

Common Lisp用のメッセージキュー「Psychiq」を作りました

$
0
0

2年前にLesqueという、Common Lisp向けにRubyのResqueクローンを作りました。

メッセージキューやジョブキューという種類のプロダクトで、非同期処理を別のプロセスに移譲してバックグラウンドで行うものです。Redisをバックエンドとしています。

ある程度の規模のWebアプリケーションなんかを運用しているところなら必要になってくるだろうものですが、Common Lispでそういうプロダクトを作っているところがあるのかどうかも怪しいです。弊社サムライトはどうなんだと言われると苦しい。

ブログでLesqueの紹介記事は書いたんですが、その後使うことも無いしQuicklispにも申請せずメンテナンスもしていませんでした。特にせっつくようなコメントももらってないので需要もないのかもしれません。

blog.8arrow.org

物好きな僕のフォロワーがRedditにも投稿しています。

www.reddit.com

RをLに置き換えるなんて日本人のユーモアうける、みたいなことが書いてあります。

Sidekiqの台頭

それから2年が経って、状況も変わりました。以前はResque一択のような空気だったメッセージキューも、今はSidekiqという競合があります。

またメッセージキューが必要そうだなぁ、という機運が高まってきたので、この機会にもう一度Sidekiqのアーキテクチャをベースとして懲りずに再実装してみるかと思いました。

そして作ったのが「Psychiq」です。

Resque vs Sidekiq

ResqueもSidekiqもRedisを使ってジョブを処理するのは同じですし、SidekiqはResque互換であることも強調しています。

SidekiqのWebサイトを見ると他の競合製品より最大20倍速いなどと謳われています。高速で並列に大量のジョブを処理することを売りにしているようです。

スレッドベースのアーキテクチャ

違いはアーキテクチャにあります。

Resqueはワーカーをforkで子プロセスで立ち上げ、それぞれのワーカーがジョブをRedisからデキューして処理します。

一方のSidekiqはスレッドで処理します。スレッドのほうが軽量なので、多くのワーカーを起動できます。デフォルトでは25個のスレッドを立ち上げます。

また、スレッドのほうがメモリ空間を共有できるため、ワーカーをまたいだ処理が高速でシンプルに書けます。具体的には処理したジョブの数は失敗したジョブの数などの統計情報を記録する処理などがそれに当たります。

Redisに完全依存

SidekiqはバックエンドがRedis一択で、Resqueのように他のものを使うことができません。

これは欠点のように見えますが、実際はコードベースも小さくシンプルでメンタナブルに保つのに一躍買っているようです。バックエンドが増えるとそれぞれのバックエンドで挙動が変わらないことのテストとか書かないといけないし、大変だしね。

Psychiq

PsychiqはSidekiqのほぼ完全なCommon Lisp移植版です。Redisをバックエンドにしたメッセージキューで、Resque/Sidekiq互換になっています。

Worker (ジョブを処理するコード) を書く

まずは非同期処理をする部分を書きます。これはメインアプリケーションと、Psychiqプロセスで共有するコードなので独立したASDFシステムにしておくのが望ましいです。

引数を受け取って何か処理を行います。返り値は特に使われません。

(defclass my-worker (psy:worker)())(defmethod psy:perform ((worker my-worker)&rest args);; Do something)

メインアプリケーションでenqueueする

メインアプリケーションでジョブをenqueueします。先ほどのワーカークラスを指定し、引数リストを渡します。

;; ジョブをenqueueする(psy:enqueue 'my-worker'("arg1""arg2"));; 300秒後にジョブをenqueueする(psy:enqueue-in-sec 300'my-worker'("arg1""arg2"));; 複数のジョブを同時に追加する;; ループで回すよりも効率が良い(psy:enqueue-bulk 'my-worker'("arg1""arg2")'("another""one") ...)

このデータはRedisに記録され、Psychiqにより処理されるのを待ちます。

Psychiqプロセスを立ち上げる

非同期でジョブを処理するPsychiqプロセスを立ち上げると処理が始まります。このプロセスは通常は立ち上げっぱなしにします。

Roswellスクリプトが提供されているのでコマンドラインから起動できます。そういえばLesqueを作ったときにはRoswellスクリプトなんてなかったんですよね。

現在はQuicklispに登録されていないのでまずはGitHubからインストールが必要です。*1

$ cd ~/common-lisp
$ git clone https://github.com/fukamachi/psychiq
$ ros -l psychiq/psychiq.asd install psychiq
# ~/.roswell/bin/psychiq がインストールされているはずです
$ psychiq --host localhost --port 6379 --system myapp-workers

これでメインアプリケーションでenqueueが行われるたびに、Redisを介してジョブがこのPsychiqプロセスに渡り、非同期で処理が行われます。

失敗したジョブはどうなるか

ジョブの処理中にerror conditionが発生するとジョブは失敗したものとして扱われます。

失敗したジョブはfailedキューに移動し、間を置いてから再度enqueueされて自動リトライされます。一定回数の失敗を繰り返すとdeadキューに移動します。

逆に言うなら、ジョブを処理中に失敗として扱いたいときはerrorを発生させれば良いわけです。

Web UI

PsychiqにはResqueやSidekiqのようなWeb UIはありません。しかし、Resque/Sidekiq互換なので、SidekiqのWeb UIを流用することができます。

以下のようなconfig.ruを用意し、

require'sidekiq'Sidekiq.configure_client do |config|
  config.redis = { :size => 1, url: 'redis://localhost:6379', namespace: 'psychiq' }
endrequire'sidekiq/web'
run Sidekiq::Web

Rackサーバを起動します。

$ rackup config.ru

http://localhost:9292/busyを開くと以下のような画面が見えます。

f:id:nitro_idiot:20160118174428p:plain

左上のロゴが「Sidekiq」なので不思議な感じがしますが、Psychiq用のRedisキューを読み込んで情報を表示しています。

ここから実行中のプロセスやジョブを一覧したり、失敗したジョブの手動リトライなどができます。

おわりに

以上、Psychiqを紹介しました。いつも通りGitHubで公開しています。ライセンスはLLGPLです。

そういえば、今月末はLisp Meetupがありますね。

lisp.connpass.com

今回のテーマはCommon Lispです。特にPsychiqの話をする予定はありません。

takagiさんの「Common Lisp Scriptの話」が気になります。フロントエンドもCommon Lispで書ける未来も近いんでしょうか。

どうぞ奮ってご参加ください。

*1:現在Quicklisp Alpha distには含まれています。1月のリリースには含まれる予定です。

プログラマを志す中高生向けの文章をマグロ部に寄稿しました

$
0
0

f:id:nitro_idiot:20141102032556j:plain

朝日新聞の中高生向けウェブメディア「マグロ部」にプログラマの記事を寄稿しました。

「人生のOB・OG訪問」の「夢を叶える方法」というシリーズで、将来の夢を考える若者向けのインタビュー記事を連載するものです。

たとえば先月の「キャビンアテンダンド」の人のインタビューはとても面白かったです。この方は一度就職して社会人を経験したのちにキャビンアテンダンドになったという、「へぇ、そういう道もあるんだ〜」と素直に興味深く読みました。中高生違うけど。

で、他の人はインタビューなんだけど、僕だけなぜか記事書いてくれって話で。

プログラマになりたい中高生って多いと思うんですよ〜」 「そうなんですか」 「それでプログラマとして活躍されている深町さんに記事をお願いできないかなと」 「え、それ僕でいいんですか」

プログラマとして活躍してる人とかもっと他にいるだろ……とか思いつつ。最初に思い浮かんだのはまつもとゆきひろさんなど名のある人とか。

けれど、マグロ部を見てみて、どうやら老練のプログラマよりも中堅 (たぶん30代くらい) の人に話を訊いているんだなと思って承諾しました。

「プログラミングを始めたきっかけとか書いてほしいです」

とか言われても、8歳のときには一人でLisp処理系を書いたとか伝説的なエピソードがあるわけでもありません。高校時代は不登校で引きこもって昼夜オンラインゲームをやっていたとか、そんな冴えない過去ばかり。プログラミングを始めたのも周りよりずっと遅いですし。

現在のことも、僕がシリコンバレーのイカしたスタートアップででも働いていればかっこいいことも書けるんだろうけど、僕がやっているOSSのことなんかはなかなかわかりづらいものだと思います。

けれど、もうありのままに書いてしまおうと思って書いたのがこちらの記事です。

落ちこぼれだった私が、プログラマとして企業を越えて自由に生きる「夢を叶える方法」 | マグロ部

中高生向けなので少し説明的だったり簡易な表現になっていますが、ブコメを見る限り内容的には大人が読んでも少しは楽しめるものになっているのかなと思います。

良ければ読んでみて、今後の進路を考えている知り合いなどいらっしゃれば参考に紹介していただけると書いた甲斐があります。

落語Botを作った & LINE Botの設計考察

$
0
0

僕はよく落語を聴きに行きます。

寄席のときもあるし、お気に入りの落語家が出演する落語会のチケットを買って行くこともあります。寄席と落語会を合わせてだいたい月に3回くらい。

「寄席」というのは都内の各所で1年365日やってる落語イベントです。都内には新宿、池袋、上野、浅草に席亭があります。途中から入ったり途中で帰ったりが自由なので「あー、落語聴きに行きたいなー」というときに気楽にいけます。

そういうときにはどこの席亭の寄席に行こうかな、と当日の出演スケジュールを見て決めることになります。

ところがこれが意外と面倒くさい。

それぞれの席亭の本日の番組表を複数窓で開いて見比べるわけですが、一昔前のWebサイトっぽさがあってあんまりスマートフォン対応してくれていません。小さな文字を見比べて「上野には誰々が出るから…」とか思案するわけです。

落語Bot

そういう事情もあって、LINEで寄席の情報を調べられるBotを妻と作りました。プログラムとインフラ運用、ランディングページ作成は僕が担当しました。

下部の「本日の定席」というメニューを開くと都内4席亭のロゴが出るので、行きたいところをタップすれば出演者をずらずらっと出してくれます。

f:id:nitro_idiot:20161129064924p:plainf:id:nitro_idiot:20161129064939p:plain

もう一つの機能では落語家の名前を言うとその落語家の出演予定をCarouselで教えてくれます。

f:id:nitro_idiot:20161129065551p:plain

すげー便利。

LINE BOT AWARDS

落語Botは「LINE BOT AWARDS」にエントリー予定です。

割と本気で家庭用Slack Botを作った自分としては参加しないわけにもいかず。むしろ運用経験を活かして積極的にグランプリ狙っていきたいくらいの気持ちでした、が、落語Botで1000万って無理だよね。

さらに言えばSlack BotとLINE Botはちょっと勝手が違います。良いところもあれば使いづらいところもあり、単純に移植しても良いものはできそうにありません。LINE Botの特徴を活かして設計しないとダメそうです。

LINE Botではプッシュ通知に依存できない

一番大きい特徴というか、LINE Botの制約は、プッシュ通知をするためには月額料金が必要ということ。

Developer TrialとPro (21,600円/月)でしかプッシュ通知はできません。Developer Trialは無料ですが友だち数に制限があり、プランの変更もできないのでサービスインするならProが唯一の選択肢です。

※追記 (12/10): LINE BOT AWARDSにエントリーすると3月中旬まではすべてのプランでpush APIが使えるようです。

こんなもの払う前提で作ってたらBot作って1000万どころか運用するだけで赤字です。現状Botを作ってユーザーから集金するシステムをLINEが用意してくれてないのでどうしようもありません。

僕が以前作った家庭用Botではプッシュ通知が機能の大半を占めます。毎日天気を教えてくれたり、よく使う電車の路線の遅延情報を教えてくれたり、宅配便の到着予定を教えてくれたりします。けれどこういう機能をLINEに移植するだけで出費です。

落語Botでも、お気に入りの落語家を登録して、その落語家の出演予定をプッシュ通知で教えてくれると便利なんですが、こういう事情でつけられずにいます。

仲間内で使うならLINE Notify使えばいいんですけど、不特定多数に使ってもらうつもりなら選択肢に入りません。

そういう事情でLINE Botのメインの使い方は、能動的にBotに話しかけたときに返信するというプル型の使い方になります。なので落語Botみたいに「○○を検索して」→検索結果 みたいなものが主流になるのではないかと予想しています。

認証不要で導入が楽

LINEのほうが良いところもあり、その最大のものはユーザー認証が不要なところです。

リクエストが飛んできた時点でLINEユーザー固有のIDがついています。数タップで友だち登録するだけですぐ使えるので導入の障壁が圧倒的に低いのがメリットです。

おわりに

まとめると、僕が思うLINE Botの特徴は、

  • プル型のツール的使い方が主
  • チャットインターフェイスを活用した柔軟なサービス提供が可能
  • 認証不要で導入障壁が低い

って感じですかね。

ちなみに落語Botの開発にはCommon Lisp用のLINE BotSDKcl-line-bot-sdk」を使いました。拙作ですがCLOSを使ってなかなか上手く作れていると思います。

落語Botは以下のリンクから友だち登録できます。興味があれば使ってみてください。

友だち追加

※追記(2016/11/29 19:02):
Japaaanさんに掲載していただきました! mag.japaaan.com

Day 1: Prove

$
0
0

これは fukamachi products advent calendar 2016の1日目の記事です。

最初なのでこのアドベントカレンダーの説明をしておくと、僕が今まで作ったプロダクトをネタとして年代を追って話をするというとても気楽なものです。酒でも飲みながら昔話を聴いているというつもりで毎日お付き合いください。

始まりはShibuya.lispHackathon

僕が最初にCommon Lispライブラリを作ったのは2010年の10月でした。

ある日曜日、青山にあるセキュリティの厳重な日本オラクルのオフィスを借りてShibuya.lisp Hackathon #1というイベントが開催されました。主催はShibuya.lispの運営の1人のyshigeruさん。当時はオラクル社員だった@ymotongpooさんが会場の案内をしてくれたことも覚えています。

その頃の僕はCommon Lispのプロダクトなんて一つもなくて、ClojureS式で書けるプレゼンツールを公開したりしていました。仕事ではアリエル・ネットワークという会社でJavaを書いていました。

6年前のCommon Lispのライブラリ環境

Clojureから入った僕にとって、当時のCommon Lispのライブラリ環境は貧弱でした。Quicklispがようやく数週間前にリリースされたばかり *1でまだ全く普及しておらず、まだ存在すら知らない人もいたほどです。

ライブラリのインストールにはasdf-installというツールを使っていました。これは現在どの言語にもあるような中央管理型のパッケージシステムなんかではなく、独自にHTTPアクセス可能な場所にtarballを置いてCLikiにページを作るという素朴なもの。まだ今ほどにGitHubを誰でも使っているというわけでもなかったので、自前のサーバにホスティングするものだからそのサーバが落ちているとライブラリがダウンロード不可能だったりして。ダウンロードはできてもそれぞれのライブラリの結合テストなんてされてないので、バージョンが上がる度にコンパイルエラーが出るなんて珍しくありませんでした。

テストフレームワーク

そんなときにCommon Lispに入門していざプログラムを書こうと思った矢先、テストフレームワークがどうも求めるものがない。Clojureclojure.testPerlTest::Moreのようにシンプルなものはlisp-unitというものがあったのだけど、出力がTAP (Test Anything Protocol) 形式ではない。

ないなら作ってしまえという短気さで、Hackathonで作ることにしました。

名は「CL-TEST-MORE」で、PerlTest::MoreAPIを移植したようなものです。スクリプトとしてテスト実行できるところや、ASDFだけでなくcl-test-more.lispのファイル一つをロードするだけで使えるという手軽さ、そして出力がTAPであるという点を特徴としていました。

Hackathonの終わりの発表会で早速発表しました。

終わったあとに@imakadoさんから「TAP形式だとHudson (Jenkins) でも使えて便利ですね!」と言われたのをなぜかよく覚えています。

ASDF対応から、Proveへ

当然ながらその後の僕の作ったプロダクトはすべてCL-TEST-MOREを使ってテストを書いていくことになります。それに応じてCL-TEST-MOREも進化してきました。

Quicklispの普及に伴ってスクリプトとして実行できるという要求がなくなったので、ASDFでの利用を主眼としたりして。

その後、JenkinsでのテストからTravis CIでのテストが主流になってTAP形式が今ほど重要ではなくなったた全面的に書き直すことになり、出力形式を増やして成功と失敗で色付けしたりモダンな見た目を目指しました。名前もより短く「Prove」に変更しました。

現在はRoswellスクリプトの「run-prove」を使うことでコマンドラインから簡単にテストを走らせることができるようになっています。Travis CIで走らせるテストなどにはとても便利です。COVERALLS=trueにするとカバレッジを計測してcoveralls.ioに投稿する機能もあります。

テストという一歩

当時は確かテストファーストとかが声高に言われていたような時代で、言語に関わらず公開するプロダクトには自動テストを書こうという風潮が強くなっていた頃です。

その中で、今後Common Lispでプロダクトを継続して作っていくならば、まずはこの一段を盤石にしなければならないという思いがありました。

ちなみに当時の僕がShibuya.lispのLTで発表していたスライドが出てきたので貼っておきます。かなり過激で強気ですが、当時はこれくらいの勢いがないとやっていけなかったのでしょうね。

Lispで仕事をするために / SlideShare

おわりに

ProveはGitHubで公開しており、現在Starは107。95のプロジェクトで利用されています。

明日のアドベントカレンダーは2日目のClackについてです。お楽しみに。

*1:ハッカソンが10/24、Quicklispのリリースの10/7の17日後です

Day 2: Clack

$
0
0

これは fukamachi products advent calendar 2016の2日目の記事です。

今日はClackについて話します。

YAPC Asia 2010 keynote

僕が最初に学んだプログラム言語はPerlでした。その後PHPでのアルバイトを経験しましたが、好きな言語はやはりPerlでした。

最初に参加したカンファレンスはYAPC::Asia 2009だったと思います。まだPerlを始めて数年の若者で、技術力なんて吹けば飛ぶほどのものです。

当時はPerlにもまだ勢いがあり、YAPCは日本最大規模のカンファレンスでした。いろんな人が入れ替わりでPerlの話をし、ある人は自分のプロダクトのこと、ある人は会社での運用について、またある人はPerlの言語自体のことなど、内容はさまざまでした。そのとき受けた刺激は僕のプログラミング活動に大きく勢いをつけ、いつか自分も壇上に立てたらいいなと憧れていました。

特に僕に影響を与えたのは翌年YAPC::Asia 2010のmiyagawaさんのKeynoteスピーチでした。

最近のmiyagawaさんはrebuild.fmのオーガナイザーとして知っている方も多いかもしれませんが、その頃はPSGI/Plackの作者として、サンフランシスコにいながらPerlコミュニティの中心人物です。

彼のKeynoteは今でも動画で見ることができます。

これを聞いて、彼がWSGIやRackから影響されてPSGI/Plackを作ったように、僕にも何かができるのではないか。そういう単純な無邪気さで僕は、彼がPerlコミュニティにしたことを、Common Lispコミュニティでも目指すことに決めたのです。

6年前のCommon LispのWeb事情

6年前のCommon LispのWeb周りの状態は、今考えると悲惨なものでした。

Webフレームワークと呼ばれるものはいくつかあった *1のですが、どれもメンテナンス状態がとても悪い。ドキュメントも不完全。RDBMSとの連携方法もわからない。デプロイ方法もわからない。実績もないため、実際に作ってみてパフォーマンス上の問題が出る可能性もあります。

軽量なWebアプリケーションであれば、ピュアCommon Lispで書かれたHunchentootというアプリケーション・サーバーを使うことも有力な選択肢でした。しかし、Hunchentoot上に構築するアプリケーションはHunchentootに依存したものになってしまうため、当然ながらアプリケーションがHunchentootにロックインされてしまいます。もしHunchentootに問題があったときにmod_lisp*2FastCGIに移行したいとなっても手がありません。

今だから言いますが、新しいWebサービスを作りたいとなったときにこの状態でCommon Lispを使おうというのは正気ではありません。

Hunchentootは当時でも「速い」と評判でしたが、まともなベンチマークなどありませんし、最近取ったベンチマークではRubyUnicornより遅いことがわかっています。各リクエストでスレッドを作るために、同時に捌けるリクエストは100までという制約もあり、大規模なWebサービス運用には不安が大きいです。

Clackで目指したもの

RubyPerlに当たり前のようにあって、Common Lispに足りないものは明白でした。安定して開発されていてカスタマイズ性があり、それなりの速度で動いて、ドキュメントが豊富な、運用実績のあるWebフレームワークです。

ではそのために何をするべきか。僕はPlackCommon Lispに移植することに決めました。

ただ作るのは簡単です。難しいのは、開発を続けることです。さまざまな人に使ってもらい、地道に改善を続けることです。

僕はこのプロダクトを、少なくとも5年は続くものにしたかった。安定して開発を続けるためにしたのは、主に4点です。

  • テストが完備されている
  • ドキュメントが豊富にある
  • GitHubでオープンに開発する
  • リリースを続ける

CL-TEST-MOREを使ってテストを書き、それをJenkinsで自動テストするようにしました。また、ドキュメントをすべての関数はもちろん、パッケージにも書きました。開発はGitHubでオープンに行いました。Issueでの議論を残し、新たなコントリビューターを得たときに改良の経緯がわかるようにするためです。そして、何かしらのリリースを毎月行いました。改善が続いているというのは安心感があるものです。

すべてが思い通りにいったわけではありません。Common Lispコミュニティに歓迎されたかと言えばそれほどでした。けれどそれもある程度予想していたことですし、当時の僕はいつか皆が振り向いてくれるだろうということを楽観的に信じていました。

Clackの思想

Clackが"異質"だったのは新しいというだけでなく、それがとても「思想的な」プロダクトだったことだと思います。

Clackをリリースしたときの僕のブログエントリはそれなりの反響がありました。

ここではHunchentootが密結合のアプリケーションを作ってしまうことを「そびえ立つクソ」だと形容しました。それに対してClackは疎結合を奨励します。裏側のWebサーバーに依存せず、Webフレームワークやアプリケーションコードも小さなコンポーネントの組み合わせによって構築します。

疎結合にすることはアプリケーションのテストを簡単にし、他人との協力した開発を容易にします。他のライブラリとの依存性も減らせるため、他のライブラリが朽ちたときに致命的な影響を受けません。結果的に開発の継続性が高まることが期待できます。

面白いと思ったのが、このエントリに肯定的なコメントをしているのはLispプログラマではない人ばかりであることです。コミュニティの外にいる人がこの記事を読んで、Common LispでもWebアプリケーションを書けるのか、魅力的だな、と思ってもらえたのだと考えれば喜ばしいことですし、そういう人を取り込んでいくことはLispコミュニティにとっても重要なことでした。

もちろん、Clackがあるだけで大きくWeb開発の環境が改善したわけではありません。その点僕の当時の態度はただの虚勢ではありましたが、それでもいつか本当に楽園を作ってみせようという強い決意はありました。そして現在それはかなりの割合達せられていると感じています。

v2のリリースと、Lackへの分離

年月は過ぎて1年半前、Clackはv2.0.0をリリースしました。

このリリースではWebアプリケーションの構築部分 (ミドルウェアなど) をLackという新しいプロジェクトに分離し、Clackはバックエンドサーバーの抽象化ライブラリになりました。ただ分離しただけでなくLackはスクラッチから書き直し、Clack v1とは後方互換性はありません。主に高速化を意図して行い、結果としてさらに疎結合性が高まりました。

おわりに

ClackはGitHubで公開されており、現在Starは565です。これは僕のプロダクトで最も高い数字です。

明日のアドベントカレンダーは3日目のCavemanについてです。お楽しみに。

*1:Weblocksやweb4r

*2:Lispプロセス動かすApacheモジュール。今は死んだ

Day 3: Caveman

$
0
0

これは fukamachi products advent calendar 2016の3日目の記事です。

今日はCavemanについて話します。

Clackに対するコメント

Clack のリリースエントリは僕にとってはかなりの反響がありました。

その当時の記事についたはてなブックマークコメントで面白いものがあるので紹介します。

f:id:nitro_idiot:20161202224033p:plain

この id:kdaibaさんのコメントは全く的を射ていて、賞賛でもなく批判でもありません。そして僕自身もClackがゴールだとは微塵も思っていませんでした。

Webフレームワーク

次に必要なのはWebフレームワークです。Clackを直接使うこともできましたが、やはりどのアプリケーションにも共通の部分というのはあります。たとえばURLディスパッチャ。それからテンプレートエンジンとの連携。環境による設定の切り替えなどがそうです。

僕はすぐにWebフレームワークの開発に取り掛かり、Clackのリリースからちょうど1ヶ月後にリリースしました。名前は「Caveman」です。

この名前に特に面白い由来があるわけではありません。Clackとは異なり何かユニーク性の高い名前をつけたいと思って m2ymさんと話しており、「かわいい名前よりも強そうな名前にしよう」という方向性だけ決まったのち、ふっと頭にこの名前がよぎったためにつけられました。

俗に言うマイクロWebフレームワークで、Sinatraのようなものと同等の機能を備えていました。アーキテクチャの参考にしたのはPerlAmon2です。ここでもPerlコミュニティからの影響を受けています。

アノテーション記法

Cavemanの目新しく特筆すべき点は、Common LispアノテーションAPIとしてユーザーに提供した初めてのプロダクトというところでしょう。

@url GET "/hi"
(defun say-hi (params)
  "Hello, World!")

@urlの行に注目してください。

Lispというと括弧ですべてプログラムを構成するような印象を持っている方がほとんどだと思いますが、このコードでは@urlという宣言があります。

Common Lispにはリーダーマクロという自由に構文を定義する機能があり、この@urlという部分はcl-annotというアノテーションライブラリを使って定義しているのです。

昨日のClackの記事で、「Clackは思想的」と言いました。それは疎結合と再利用性に留まらず、Common Lispの新しい書き方も推進しようという意欲的なものであり、その一つがこのアノテーション記法でした。ゆえに僕のその以後のプロダクトの多くは必要以上と言えるほどにcl-annotを使って書かれています。

このCavemanの、アノテーションによるURLディスパッチャは評価のわかれるものでした。好きな人はこの記法があるためにCavemanを好んで使い、そうでない人は顔をしかめました。

4chanに「そんなに好きならPythonを使ってろよ」という書き込みがあったことを覚えています。面白い意見です。Lisperは普段から「括弧が多いという見た目など表面上の問題だ」と言ってシンタックスのある言語を批判しますが、そのLisperがアノテーションを表面でしか見ずに批判するのは皮肉なものです。

なぜ僕がcl-annotを推奨していたかは以下のエントリに詳しく書きました。

blog.8arrow.org

RESTAS

同時期に作られたWebフレームワークがあります。そのRESTASというフレームワークは、軽量であることは共通ですが、ClackではなくHunchentootをベースとして作られていることが違います。

面白く思ったのが、作者のarchimagも同時期にバックエンドサーバーに依存しないレイヤーの必要性をHunchentootのメーリングリストに投稿していたことです。しかし彼が想定していたのはHunchentootと同じ比較的リッチなAPIを提供するものであり、RESTASがClackを使うことはありませんでした。

作者がロシア在住であることもあり、RESTASはEUのコミュニティである程度受け入れられていたように見えます。CLikiはRESTASで作られていますし、まともな実績のないCavemanよりはユーザーはいたのではないでしょうか。

Caveman2

それから2年後。Cavemanはフルスクラッチで書き直され、「Caveman2」としてリリースされました。

blog.8arrow.org

機能が増えてマイクロWebフレームワークからスモールWebフレームワーク程度になりました。現在、Common Lispでデータベースと連携する機能が標準でついている唯一のWebフレームワークです。

「THE REAL FRAMEWORK」という売り文句で強気ですが、まったく冗談のつもりはありません。Common LispでWebアプリケーションを作ろうと思うなら現状唯一と言えるほどの存在だと思います。

おわりに

CavemanはGitHubで公開されており、現在Starは388です。

明日のアドベントカレンダーは4日目のcl-projectについてです。お楽しみに。


Day 4: cl-project

$
0
0

これは fukamachi products advent calendar 2016の4日目の記事です。

今日はcl-projectについて話します。

コーディングスタイルの提唱

前回の記事のCavemanからは話が前後します。

Clackの思想は疎結合性と再利用性を高めることでした。それはClackを使ったアプリケーションだけでなくClack自身についても同様であり、つまりは一般的なCommon Lispアプリケーション自体の疎結合性を高めることも目指したものでした。

Common Lispにはアプリケーションの分割単位として「パッケージ」と「システム」があります。「システム」はプロジェクトの一つの読み込み単位であり、複数のファイルと複数のパッケージを含みます。

他のプログラム言語に親しんだ人には違和感があるかもしれませんが、Common Lispのパッケージはファイル単位と結びついていません。つまり、1ファイルに複数のパッケージを書くことができますし、1つのパッケージを複数のファイルで共有することもできます。

従来のCommon Lispアプリケーションで一般的だったのは、package.lispというファイルにdefpackage (パッケージ定義文) をまとめてしまい、それぞれのファイルでは一つのパッケージを共有するものでした。

このスタイルにはいくつもの問題があります。

  • ファイルに分割されていてもシンボルの衝突が起こる
  • 依存ライブラリが実際にどのファイルで使われているかわかりづらい
  • defpackage宣言が同一ファイルにないため管理がおざなりになりがち

特に依存ライブラリやファイルの依存関係がわかりづらくなることが大きな問題です。

そこでClackでは1ファイルにつき1パッケージのスタイルを提唱しました。そして:useの使用を極力やめ、必要なシンボルを:import-fromで列挙することにより依存しているシンボルを一覧できるようにしました。これらはAriel LabsのCL Style Guideで詳しく書いています。

提唱から布教へ

その頃僕はいくつものCommon Lispライブラリを並列で作り始めていました。Common Lispライブラリを作り始めるときに.asdファイルを作ったりREADMEを置いたりテストファイルを配置したりなど、何度も同じことをしなければなりません。

そこでこれをテンプレート化してライブラリの雛形を生成できるライブラリを作りました。それが「cl-project」です。

生成される雛形のプロジェクトは当然ながら僕が推奨するスタイル、Clackスタイルのプロジェクト構成でした。ファイル毎にパッケージが定義され、READMEがあり、テスト用のファイルも同時に生成されます。

競合としてQuicklispのZackが作ったquickproject というものもあります。こちらを愛用している方もいると思いますが、違いとしては1パッケージ1ファイルのスタイルではないことと、テストの雛形は生成されないことです。

この地味な名前のプロダクトは実は僕のプロダクトの中ではかなりよく使われている部類です。

普及のためという戦略的な意図はなかったにせよ、結果的にClackスタイルの布教にも貢献をしました。現在では新しいプロダクトの多くは1パッケージ1ファイルのスタイルで書かれ、Proveが使われたプロジェクトも多いです。

おわりに

cl-projectはGitHubで公開されており、現在Starは69です。

明日のアドベントカレンダーは5日目のningleです。お楽しみに。

Day 5: ningle

$
0
0

これは fukamachi products advent calendar 2016の5日目の記事です。

今日はningleについて話します。

Cavemanをもっと小さく

CavemanはマイクロWebフレームワークではありましたが、一般的なものと違ってプロジェクト雛形生成機能がついていました。

PerlのAmon2から影響されて作られたので当然と言えば当然なのですが、RubySinatraPythonのFlaskのようにまずは1ファイルでさらっと書いて起動できるといった手軽さに比べると鈍臭く感じてしまいます。

これはCavemanが悪いわけではありません。他のフレームワークがURLディスパッチャしか提供していないのに対し、Cavemanはテンプレートエンジンとの連携や環境による設定の切り替えなども含まれ、プロジェクトのディレクトリ構造がある程度固定されるのです。

けれども仮に、そこを敢えて1ファイルだけで完結できるようなフレームワークにするならどのようなものだろうと思いつき、それを作ってみることにしました。

そのフレームワークが「ningle」です。

名前の由来はアイヌ伝承の小人「ニングル」です。Cavemanが無骨な原始人とすれば、ningleは可愛げのある小人だというわけです。

アノテーションではなくsetf

3日目のCavemanの記事で、アノテーションによるルーティングルール定義について話しました。一方でningleはsetfを使った定義をします。

(defvar*app*(make-instance'ningle:<app>))(setf(ningle:route *app*"/")"Welcome to ningle!")(setf(ningle:route *app*"/login" :method :POST)
      #'(lambda(params)(if(authorize (cdr(assoc"username" params :test #'string=))(cdr(assoc"password" params :test #'string=)))"Authorized!""Failed...Try again.")))(clack:clackup *app*)

Common Lispsetfは代入の意味ではありますが、その動作は自分で定義することができます。setf ningle:routeはappのルーティングルールに追加するという挙動です。

なぜ今回はアノテーションを使わなかったのか。それはningleが小さいだけでなく単純でなければならないという設計思想が所以でした。

新しいアノテーションやマクロはユーザーに使い方を覚えてもらう必要があります。一方でsetfはCommon Lispの標準の機能であり、親しみやすく、学習コストも下がります。

Lispのマクロは強力です。マクロがあるからLispを使うといっても過言ではありません。けれど、それはむやみに使えばいいというものではありません。学習コストと天秤にかけて、利便性が勝るときだけ使うから光るのです。

さらにningleでは、Clackにある機能は隠蔽せずにそのまま使うことにしました。このためningleではClackの使い方を知っていることを前提としてはいますが、その分Clackに親しんだ人には扱いやすく感じると思います。

これらの違いがningleを機能の少ないCavemanではなく、シンプルで取り回しの効くマイクロWebフレームワークにしたと自負していたのですが、誤算もありました。

Caveman vs ningle

ningleをリリースしてからとても多くの人にGitHubやメールなどで同じ質問を受けました。

「Cavemanとningleの2つあるようだけど、違いは何?どちらもマイクロWebフレームワークと書いてある。どちらを使うべきだろう?」

好きな方を使えばいいだけなのですが、選択肢が多いと不安になる気持ちもわかります。

同じ質問に答えるのに飽き飽きしていた僕は、そこでCavemanをより進化させ、完全にningleとの差別化を図りました。そういった経緯で作られたCaveman2はRDBMSとの連携が標準対応しており、一般的なWebアプリケーションで必要な最小限のものは揃えてあります。

また、Caveman2はなんとningleに依存しています。内部のURLディスパッチャ部分をningleを使うことで、階層的なプロダクトであることが明示できるとともに、Clackの思想である再利用性を実現しています。まあ、似たコードを2つメンテしたくないっていうのもあったんですけど。

それからのWebアプリケーションはCaveman2で作るほうが一般的になり、ningleはアプリケーション内に埋め込むような小さなHTTPアプリケーションとしての用途で使われることが多くなりました *1

おわりに

ningleはGitHubで公開されており、現在Starは110です。

明日のアドベントカレンダーは6日目のcircular-streamsについてです。お楽しみに。

*1:たとえばQlotのQuicklisp dist配布用のモックサーバーなど

サムライト株式会社を退職します

$
0
0

今年末12月31日でサムライト株式会社を退職することにしました。

2年間という短い期間ではありましたが、Common Lispでの開発を存分にやらせていただきました。おかげで高速なWebサーバーのWooの運用実績ができ、Common Lispが実用に足るだけでなく他の言語を凌ぐパフォーマンスを出せるということが実証できたと思います。

次の雇用先は決まっていないのでこれからのんびり探す予定です。

もし雇ってもいいという企業がいらっしゃれば、退職と雇用先の募集についてをご覧ください。

Day 6: circular-streams

$
0
0

これは fukamachi products advent calendar 2016の6日目の記事です。

今日はcircular-streamsについて話します。

circular-streamsとは

これまでのプロダクトとは違ってcircular-streamsは裏側で使われているライブラリなので知らない人も多いと思います。

Common Lispのストリームはreadを始めて一方向に読み込みを進めます。一度readしたものは基本的に戻すことはできません。ストリームの終端まで来るとEOFになります。

この性質は他の言語でも一般的なものだと思われます。けれど、複数のコードから一つのストリームを共有するような場合に問題になります。なぜなら先に走ったコードがストリームを読み終わってしまうと、もう一方がストリームを読みに行ってもEOFが帰ってきて読み込めないからです。

これはClackのアーキテクチャにとっては不利な仕様です。

複数のミドルウェアでリクエストボディのストリームを共有していると、前のミドルウェアが全部ストリームを読んでしまった場合にbody-parametersを読めなくなってしまいます。

circular-streamsはこの問題を解決します。

make-circular-streamsでストリームをラップすると、EOFまで読んだあとにまた再び最初からreadすることができます。内部的にバッファを持っており、一度読んだものをまるでストリームから読んだかのように見せます。

(defparameter*stream*(flex:make-in-memory-input-stream
               #(72101108108111)))(defparameter*circular-stream*(make-circular-stream *stream*))(read-char*circular-stream*);=> #\H(read-char*circular-stream*);=> #\e(read-char*circular-stream*);=> #\l(read-char*circular-stream*);=> #\l(read-char*circular-stream*);=> #\o(read-char*circular-stream*nil :eof);=> :eof(read-char*circular-stream*);=> #\H

面白いでしょう?

おわりに

circular-streamsはGitHubで公開されており、現在Starはたったの2です。寂しい。

明日のアドベントカレンダーは7日目のcl-dbiについてです。お楽しみに。

Day 7: CL-DBI

$
0
0

これは fukamachi products advent calendar 2016の7日目の記事です。

今日はCL-DBIについて話します。

フレームワークバトルは次のステージへ

Cavemanに一定数のファンがついた頃、Star数がRESTASに並びました。そのとき僕はうれしくて、@snmstsさんに言いました。「佐野さん!CavemanがようやくRESTASを超えたよ!」

すると佐野さんが言ったことはCommon Lispフレームワークの歴史的な一幕です。

「もうCommon Lispフレームワーク同士で争っていても仕方がない。他の言語と比較して優位性が出せなければ」

他の言語のフレームワークと比較してCavemanはどういった利点があるのか、ということを言えなければCommon Lispの導入など到底できないということです。

なんでPerlを書いてるの?

はてなで働いている頃の話。確か東京から@m2ymさんが遊びに来たときだったと思います。はてなエンジニアたちで御池通間之町を下がった「みまでり」という店に行きました。奥の階段を昇って2階の手前のテーブルに座ったことまで覚えています。

酒も2杯目くらいでほどほどに料理も食べたとき id:antipopさんがおもむろに「にとろ君、なんでCommon Lispで(仕事のコードを)書かないの?」といつもの調子で絡んできました。

いつもの調子、というのは、僕が個人的にCommon Lispが好きであり趣味のコードはCommon Lispで書いているにも関わらず仕事で平気な顔でPerlなんて書いているのか、全部Common Lispにしちゃえよ、という無責任な煽りです。

ひょっとするとCommon Lispで書くことや技術力に自信がないからじゃないの?という含みもあったかもしれません。

もちろん僕はCommon Lispが好きですが、すべてのプログラムをCommon Lispで書くべきだと思っているわけではありません。ライブラリや結合予定のアプリケーションとの都合もあります。チームで開発する場合は自分以外のメンバーのスキルセットも考慮する必要があるでしょう。やりたいことと天秤にかけて実現可能性が高いほうを選びます。Common Lispで書いてもプロジェクトが失敗すれば意味ないですからね。

当時、はてなの規模のWebサービスCommon Lispで書くのはかなりチャレンジングだったでしょう。そして実現可能性はPerlに比べて極めて低かったです。僕がそのときantipopさんに言ったマジレスの一つはDBIの欠如でした。

DBI

DBI (Database independent interface) とは使うRDBMSに依らずに統一したインターフェイスを提供するライブラリです。最近の言語では標準ライブラリとして付属していて当然ですが、Common Lispには標準ライブラリがありません。

Common Lispに当時あったのはCLSQLでした。ただこれが恐ろしく使いづらい。なんで使いづらいのかうまく説明できないのだけど、おそらくインターフェイスをリッチにしすぎているために抽象レイヤーが厚くなっていてわかりづらいのかなと思われます。いわゆるORMのような機能も入っていました。また、コードとしてもとても古くFFIとしてUFFIという今では非推奨となっているライブラリを使っています。開発も止まっておりメンテナンスも十分ではないようです。

これを改善していくよりも新しく作ったほうがよかろう。そう思ってより薄い抽象レイヤーで、DBの統一インターフェイスの提供のみを行うライブラリを作りました。それが「CL-DBI」です。

2つの統一インターフェイスの違い

統一インターフェイスという意味でCL-DBIClackと似ているかもしれません。

Clackは各Webサーバに対して統一的なインターフェイスを提供することで、同じアプリケーションをコードを書き換えることなくまったく別のWebサーバーで動かすことを可能にしました。一方でCL-DBIは使うRDBMSを自由に切り替えることができます。

しかし、作ってみてわかったことですが、CL-DBIの抽象化は不十分でした。

RDBMSは汎用的なSQLという言語を使ってデータにアクセスできるという意味で共通ですが、そのSQLRDBMSごとに微妙に違い、同じSQLではエラーとなる場合が多々あります。たとえばMySQLにはAUTO_INCREMENTがありますが、PostgreSQLの場合はSERIAL型を使い、実装もsequenceとしてテーブル定義とは別扱いになります。SQLiteはAUTOINCREMENTです。さらにインデックスはありません。

そのため、CL-DBIはClackのようにまったくコードを修正しなくても動く、というほど理想的ではないのです。

また、需要の面でも違いがありました。

Webサーバと違ってRDBMSの場合は複数種類を使うというユーザーが少ないです。MySQLファンはPostgreSQLは使わないですし、PostgreSQLファンはMySQLを使いません。そういう意味で、PostgreSQLだけ使うつもりの人はCL-DBIではなくcl-postgresやPostmodernで十分なのです。それにPostmodernは可搬性を捨てた代わりにPostgreSQL独自の機能が使えるというメリットを掲げています。

CL-DBIの有用性

それではCL-DBIは失敗だったのか。他の言語で当たり前になっている統一インターフェイスは間違ったデザインなのか。

結果から言えばそうでもありませんでした。

CL-DBIはとても薄い抽象レイヤーのため、Webアプリケーションで使おうと思ったらもう少し扱いやすくしたものを使いたいという願望が生まれます。そこでCL-DBIを前提としたツールが作られました。それがIntegralCranedataflyMitoなどです。

CL-DBIを使ったこれらの周辺ツールは、一つのRDBMSには依存しません。*1そのためMySQLユーザもPostgreSQLユーザも共通して使うことができます。

共通のツールを使えるということはいくつもの利点があります。知識がユーザ間で共有しやすく、コミュニティを形成しやすくなります。さらに、同じライブラリの開発者も増えることが見込めます。バグ報告も増え、クオリティの向上にも有利です。

CL-DBIは僕のプロダクトの中では結構初期からあるライブラリですが、年を減るごとに重要性は増しています。

おわりに

CL-DBIGitHubで公開されており、現在Starは74です。

明日のアドベントカレンダーは8日目のShellyについてです。お楽しみに。

*1:IntegralはSQLの抽象化ができていないためPostgreSQLに対応していません。これは後継のMitoにより解決されています。

Viewing all 74 articles
Browse latest View live