RailsライクなErlang製WebフレームワークBeepBeepをためしてみた。

Erlangで練習がてら作ったライブラリをWebインタフェースから使ってみたいなーとか思って、Erlang製のWeb開発フレームワークを調べてみてたらBeepBeepってのがありました。
他にErlyWebってのもあるようですが、今回はこちらを試してみました。

BeepBeepのチュートリアルをやってみたと、beepbeepのソースに含まれているブログの例を参考にさせて頂きながら自分なりにまとめてみたいと思います。


セットアップ
まずはgitから最新のソースを落とします。僕はホーム以下のsrcディレクトリに落としますので

$ cd src
$ git clone git://github.com/davebryson/beepbeep.git
$ cd beepbeep
$ make

以上(笑)。beepbeepはmochiwebに依存しているようですが、mochiwebのソースはdepsディレクトリ以下に入ってました。makeするとそちらも一緒にbuildされます。


プロジェクトの生成
ではプロジェクトを生成してみます。先ほどのbeepbeepディレクトリ内で以下のコマンドを実行します。

./script/new_beep.erl blog_sample ../

これで一つ上のディレクトリにblog_sampleというプロジェクトが生成されました。
ビルドと起動

できたプロジェクトに移動してビルド後に起動します。

$ cd ../blog_sample
$ make
$ ./start-server.sh

ためしに http://localhost:8000 にブラウザでアクセスすると今作ったサイトが表示されると思います。


新規コントローラの生成
Railsだとコマンド一発でコントローラやビューを作ってくれたりしますが、BeepBeepにはそういう機能はないようです。といっても、単にsrcディレクトリ以下に"[コントローラ名]_controller.erl"を作って、"views"ディレクトリ以下に[コントローラ名]と同じディレクトリ作ったらその中に適当な名前で"ページ名.html"とか作れば良いので簡単なんですけどね^^

さらにこの後見ていきますが、ビューのファイル名とかディレクトリ名も結局コントローラ内で指定するので、別に必要なければディレクトリをきらなくても良いし、まあそのへんは使用者の自由です(笑)


コントローラの編集
さて、プロジェクトを作ると最初から、srcディレクトリ内にhome_controller.erlというファイルができています。このファイルを見れば http://localhost/home/index の表示内容を変更するには home_controllerモジュールのindex関数を修正すればいいのだなと解ります(Railsなどを触った経験があればですが)。
また、home_controllerのindex関数を見れば最終的にviews/home/index.html に変数dataを渡しているのがなんとなく解るかなとw

ここで最後の戻り値のタプルの最初の要素が'render'となっています。どうやらrenderだとその後にビューのファイル名、変数のリストを入れておく決まりのようですね。

handle_request(アクション名, URLから渡された値) ->
  (なんらかの処理),
  {render, ビューのファイル名, ビューで使う変数名と値のタプルのリスト}

のようになるようです。
ちなみに、プロジェクト名_web.erl(今回はblog_sample_web.erl)の27行目付近からのコメントとソースを見ると、render以外にも沢山用意してあります。まとめますと

ビューに変数を渡してレンダリングする
{render, ビューのファイル名, ビューで使う変数名と値のタプルのリスト}
example: {render, "home/index.html", [{date, "2011/7/21"}, {name, "ひろえ"}]}

文字列をtext/htmlで返す
{text, 文字列}
example: {text, "これは文字列"}

他のURLへリダイレクトする
{redirect, URL}
example: {redirect, "/home/show/2011"}

wwwディレクトリ以下の静的ファイルの内容を返す。
{static, ファイル名}
example: {static, "/sample.html"}

なお、上記のソース内のコメントには{json, Data}という形式も書いてありましたが、実装はされていないようです。


ビューの書き方
ビューの書き方はpythonDjangoとやらにならっているそうですが、なにしろ僕はpythonを知りませんw
一つ一つ試しながら調べてみました。他にも沢山あるでしょうが必要に応じて解った事は後から追加していきます。

表示部分の開始
{% block content %}

表示部分の終了

{% endblock %}

他のファイル内容の埋め込み
{% include ファイル名 %}
example: {% include "../flash.html" %}

値の出力

{{ 変数 }}
example: {{ name }}

繰り返し

{% for 変数 in リスト %}
  (何らかの処理...),
  {% endfor %}

example: コントローラで

handle_request("index", [])
  UserList = [ [{name, "hiroe"}, {age, 35}], [{name, yomura}, {age, 36}] ],
  {render, "/home/index.html", [{user_list, UserList}]}.

のようにした場合、

{% for user in user_list %}
  <p>名前: {{ user.name }}</p>
  <p>年齢: {{ user.age }}</p>
  {% endfor %}

条件分岐

{% if 条件 %}
  (何らかの処理...),
{% endif %}

example:
コントローラ

handle_request("index", [])
  {render, "/home/index.html", [{male, true}]}.

ビュー

{% if male %}
  (何らかの処理...),
{% endif %}


セッション
beepbeepにはetsベースのセッションストアが既に用意してあります。これはbeepbeep_session_server(ソース)というプロセスを起動し、データの保存と取得を司っています。
複数台のサーバに分散するような大規模なアプリケーションであればMnesiaをつかったりするのでしょうが、とりあえずはこれで十分でしょう。

下記の変数Envはコントローラにわたってきているので、そのまま使えば良いようです。
変数Keyには任意のアトム(実際には多分Erlang項ならなんでもいいようです)を指定します。

値は任意のErlang項です。文字列でもアトムでもタプルでもリストでも。

セッションへのデータの保存
beepbeep_args:set_session_data(キー, 値, Env)
example: ok = beepbeep_args:set_session_data(name, {"HIROE", 35}, Env),


セッションデータの取得

beepbeep_args:get_session_data(キー, Env)
example: {Name, Age} = beepbeep_args:get_session_data(name, Env)

まとめ
あくまで個人の好みですが、僕はあまり大きなフレームワークが好きではありません。今使ってるメソッド等の向こう側にどれだけの連鎖した処理があるのか想像できないような大きなものはしょっちゅう調べ事や、思ったように動かない原因の調査で時間が取られてしまうからです。

其の点では、このbeepbeepおよび依存関係にあるmochiwebは、この手のフレームワークとしては非常に小さくまとまっており仕様がわからないときには比較的気楽にソースを読んで理解する事ができます。

また、Railsの弱みというか、開発はいいけど公開する段階になると途端にめんどくさくなる問題もあります。初期の頃はバックグラウンドに数個〜数十個のrailsプロセスを起動してポートを明けさせてフロントには逆プロキシをたてて..などとやたらと面倒でした。
その後、Unicornのようなものも出てきていますが、やはりフロントにはnginxなどの逆プロキシが必要、さらにいずれの方法でもOSプロセスでrailsプロセスをフォークしてるのでメモリも沢山食います。

其の点ではerlang + mochiweb + beepbeepではもともとの並列処理の強みから、そのような問題が無いと思われます。おそらく通常の場合は、フロントに逆プロキシとか立てずに、このまま公開すればいいと思います。

もちろん、外注したりされたりするようなプロジェクトでbeepbeepとかmochiwebを使う事などは殆ど無いでしょうし、そのような場合は「レールにのってるうちは理解が簡単な」Railsを使うのがベターだと思います。ただ、個人で強力なツールが欲しい場合にはerlang+beepbeepもひとつの選択肢になるように思います。