BEARで始めるWebアプリケーション開発 その10「アスペクト指向プログラミングしてみる」

今回は、BEARの特徴の内の一つである"アスペクト指向"について学びます。概要の説明は例によって本家Wikiに譲ります。

Google Code Archive - Long-term storage for Google Code Project Hosting.

アスペクト指向してみる

BEARの場合AOPは、phpdoc形式のコメントに記述する、アノテーションにより実現されていますね。

例えば、DBアクセスのあるリソースでトランザクションがかかるようにしたい場合、該当のメソッドで以下のようにコメントに書いておくだけという、何ともお手軽な感じですね。

<?php
class App_Ro_Entry extends App_Ro
{
    /**
     * リソース作成
     *
     * @aspect around App_Aspect_Transaction
     */
    public function onCreate($values)
    {
        $values['created_at'] = _BEAR_DATETIME; //現在時刻
        $result = $this->_query->insert($values);
        if ($this->_query->isError($result)) {
            throw $this->_exception('投稿できませんでした');
        }
    }
}
?>

Transactionアドバイスに関してはinit-appした時に自動的に作成されるので、わざわざ自分でアドバイスを作成する必要もなく、トランザクション処理を簡単に行う事ができます。

AOPはうまく利用すると、コードを書く量を劇的に減らす事ができますね。

アドバイスの実行順序

アドバイスは一つのメソッドに複数指定した場合、before→around→afterの順で実行され、beforeやafterが複数ある場合は、before・after毎に指定した順で実行されるようです。

<?php
/**
  * @aspect after App_Aspect_After1
  * @aspect before App_Aspect_Before2
  * @aspect after App_Aspect_After2
  * @aspect around App_Aspect_Around1
  * @aspect before App_Aspect_Before1
  * @aspect around App_Aspect_Around2
  */
?>

こんな書き方をすると、"Before2→Before1→Around1→After1→After2"という順で実行されます。

aroundに関しては複数記述した場合は、最初に記述したものだけが実行される仕様のようです。(上記例の場合、Around2は実行されない。)

アノテーション

コメント部分に書く事ができるアノテーションは、今のところAOPの@aspectと、メソッドの必須項目を定義できる@requiredが使えます。

とりあえずは@requiredだけあれば困らなさそうですが、リソースに対する入力値の事前チェックなんかをやりたいと思ったら、@aspectでチェック用のアドバイスを作っちゃえば良さそうですね。

という訳で、AOPに関してはさらっと見てみただけですが、実際には周到に最初から準備するというよりは、リソースをいくつも作っていく内に、よく出てくる処理をアドバイスとして切り出す…というような形で使っていくのが良さそうな感じがしました。

また、アノテーション機構は、実際のコードの近くに定義が来るので、コードの見通しが良くなってよいですね。DocTestも併用すれば、テストもコメント部分に書けて、そのメソッドに関する情報が一箇所に集まる感じで非常に素晴らしいですね。

次回は?

次回は、BEARでのRESTfulWebサービスの提供の方法について、またはその前段としてDIに関して書こうかなと思っています。

BEARで始めるWebアプリケーション開発 その9「フォーム関連機能を学んでみる」

今回はBEARでのフォーム関連の機能を学習します。

…とは言ってもBEARの場合、フォーム関連はPEAR::QuickFormのラッパー的な感じなので、フォームの構築方法自体はQuickFormの方を学ぶ必要がありそうです。なので、QuickFormの細かい使い方はひとまず置いておいて、今回はBEARでのフォームの使い方を学んでいく事にしたいと思います。

フォーム構築の方法

基本的な使い方は本家Wikiデモページを見ると非常によく分かるので、そちらを参照しながらフォーム構築方法を見ていきましょう。

フォームは、一つのまとまった単位(formタグで括られる範囲)毎にクラスファイルを作成して、その中でそのフォームに関する設定・処理を全て書いていくというスタイルが推奨されるようです。

という事で、よくある"入力→確認→完了"という画面遷移の場合のフォームクラスのサンプルを見ていきます。

http://code.google.com/p/bear-demo/source/browse/trunk/App/Form/Preview.php

基本的な流れとしては、フォームの状況(初期状態/確認画面/入力修正)に応じたonInjectメソッドを用意しておいて、そこで各状況毎の設定を行って、実際のフォーム部品の内容は、buildメソッドで定義する感じですね。

バリデーションルールもこのクラスの中で定義するので、このフォームに関する設定の全てが一つのクラスファイルに集まっていて、非常に見通しが良くて素晴らしいですね。

続いて、このフォームを利用するページファイルの方も見てみます。

http://code.google.com/p/bear-demo/source/browse/trunk/htdocs/form/preview/index.php

各メソッドの処理は、

onInjectメソッド
フォームの状況切り替え
onInitメソッド
DI経由でフォームクラスのbuildメソッド呼び出し
onActionメソッド
実際にsubmitボタンが押された場合の処理

という感じですね。

BEARは処理の役割分担が明確なので、一つのメソッドにダラダラ書いていく感じにならなくて、スッキリ書けて良いですね。

これだけで、Smartyテンプレート内で"{$form}"とだけ書けば、入力画面・確認画面の区別無く、必要な情報が全てレンダリングされた状態でフォームを表示する事ができます。

セキュリティに関しても、CSRFの防止や二重投稿の防止も自動的に考慮されるようになるので、難しい事を何も考えなくてもフォームでの値入力UIが作成できちゃいますね。

フォーム関連で、特に"入力→確認→完了"の画面遷移を伴う処理はとかく面倒な事が多いですが、BEARでは非常に簡単にフォーム処理ができる事が分かりました。

とは言え"簡単"という事は、QuickFormが自動的に処理している部分が多い訳で、QuickFormのデフォルトに乗っかる事ができる部分が大きければ非常に便利に使えますが、カスタマイズが必要な部分が多かったり、極めて単純なフォームの場合は、むしろフォームは自前で用意するようにした方がよいのかもしれないですね。

とりあえず、今のところQuickFormを使った方がよい程のフォームは扱わないので、今回はBEARでのフォームの扱い方をざっくり学んだ…というところまでにしておこうと思います。

次回は?

次回はアノテーションアスペクト指向の辺りを学習しようと思います。

Hadoop Hack Nightに行ってきました

米国Yahoo!HadoopチームアーキテクトのOwen O'Malleyさん来日に合わせて、技術評論社Yahoo! JAPAN主催で行われたHadoop Hack Nightというイベントに行ってきました。

定員100名と結構大規模なイベントでしたが、申し込み開始からたった1日で申し込み多数により予定を切り上げて申し込み終了になったようで、かなり注目度の高いイベントだったみたいですね。

Ustream中継もあったので細かい内容に関しては略。思った事をつらつら書いてみたいと思います。

  • Yahoo!は2007年からHadoopを利用しているとの事で、その頃から数年経って、ある程度の規模の企業ではもはやHadoopを使うのが当たり前な感じになってきた印象でした。
  • HDFSHadoop自体が不安定という発言がチラホラ出ていて、重要なデータをHadoopだけに置いて処理させるような使い方はまだ若干恐さが残る印象でした。
  • 今回のイベントのページで見て"Hadoop papyrus"というプロジェクトを初めて知ったんですが、作者の藤川さんが「本家に取り込んでもらう事を目標にする。」とおっしゃっていて、そういったLLとHadoopの組み合わせでもっと使い易くなると面白いなと思いました。
  • 英語の通訳をして頂いたのは非常に助かってよかったんですが、通訳だけで結構な時間が取られてしまっていたので、ちょっともったいないなぁという印象でした。*1

という訳で、なかなかに楽しいイベントでございました。関係者の皆様ありがとうございます。

自分の場合は、Hadoopに関しては完全に個人の興味だけで実際に使う機会は今のところ無いんですが、Webの世界の将来(あるいは既に現在)を担う技術の一つとして今後もHadoop周りには注目していきたいと思っています。

*1:自分もまずは英語のプレゼンを聞き取れるようになる努力が必要だなと痛感はしましたが…。

BEARで始めるWebアプリケーション開発 その8「リンクを使ってリソース同士を接続する」

今回は、リソース同士を接続する事ができる"リンク"の機能について学習します。

今回の題材

今までは"逆さ語"を題材としてきたんですが、現状の逆さ語の仕様だとリソース同士がリンクしていなくて、題材としてはよろしくないので、他の題材を探す事にしました。

という訳で色々考えた末、リンク機能の面白さが分かるようなものがいいかなという事で、はてなブックマークの人気エントリを題材にしてみる事にしました。

はてなブックマークの人気エントリは以下のような形で、特定のURLを含むページの人気エントリをRSSで取得する事ができます。

http://b.hatena.ne.jp/entrylist?sort=count&url=http://d.hatena.ne.jp/stellaqua/&mode=rss

ただ、このRSSにはブックマークコメントは入っていないので、コメントを見る為には該当のブックマークページを見に行かなくてはいけません。

一方、特定のページに付けられたブックマークコメントは、以下のようなURLでRSSを取得する事ができます。

http://b.hatena.ne.jp/entry/rss/http://d.hatena.ne.jp/stellaqua/20090305/1236222223

という事は、人気エントリのリソースにブックマークコメントのリソースをリンクしてやれば、人気エントリのブックマークコメントが一気に取れるんじゃね?…って事で、実際にやってみましょう。

人気エントリのリソースを作る

App/Ro/bookmarks.phpというファイル名にして、onReadメソッドを以下のようにしました。

<?php
    public function onRead($values)
    {
        $resource = BEAR::dependency('BEAR_Resource');
        $uri = 'http://b.hatena.ne.jp/entrylist?sort=count&url=http://d.hatena.ne.jp/stellaqua/&mode=rss';
        $options['cache']['life'] = 60 * 60 * 3;
        $params = array('uri' => $uri, 'options' => $options);
        $result = $resource->read($params)->getBody();
        return $result;
    }
?>

毎回RSSを取得しにいくと重たくなってしまうので、今回は3時間のキャッシュを保存する設定を追加しました。

BEARはこのように、リソース、ページ、テンプレート変数など、様々な場所でいとも簡単にキャッシュを利かせる事ができるので、多くのAPIを使うようなマッシュアップサイトでも、それなりな負荷に耐えられるWebアプリケーションを簡単に作る事ができそうですね。

ブックマークコメントのリソースを作る

続いてブックマークコメントのリソースを作ります。App/Ro/comments.phpというファイル名にして、onReadメソッドを以下のようにしました。

<?php
    public function onRead($values)
    {
        $resource = BEAR::dependency('BEAR_Resource');
        $uri = 'http://b.hatena.ne.jp/entry/rss/'.$values['link'];
        $options['cache']['life'] = 60 * 60 * 3;
        $params = array('uri' => $uri, 'options' => $options);
        $results = $resource->read($params)->getBody();
        return $results;
    }
?>

$values['link']には、bookmarksリソースからリンク機能を介してブックマーク先のURLが渡ってくるので、それを使ってブックマークコメントを取得するURLを構築しています。

人気エントリリソースからブックマークコメントリソースへリンクを張る

あとはリンク元となるbookmarksリソースのonLinkメソッドに、commentsリソースへのリンク設定を書いてやる事で、リンク機能が使えるようになります。

<?php
    public function onLink ( $values )
    {
        $links['comments'] = array(
                                   'uri' => 'comments',
                                   'values' => array('link' => $values['link']),
                                  );
        return $links;
    }
?>

当然、更に別のリソースへのリンクを書く事もできますし、commentsリソースにonLinkを書けばcommentsリソースから更にリンクする事もできます。

リンク機能を使ってページから情報を取得する

このようにリンク設定を行ったリソースから関連データを取得するのは非常に簡単で、ページから以下のような感じでごっそりと必要な情報を取ってくる事ができます。

<?php
    public function onInit(array $args)
    {
        $uri = 'bookmarks';
        $params = array('uri' => $uri);
        $this->_resource->read($params)->link('comments')->set();
    }
?>

これだけで、きちんと階層構造を持って必要な情報が取ってこれます。あとは、テンプレート側で以下のようにループを回してやれば、はてブ人気エントリのブックマークコメント一覧の完成です。

{foreach from=$bookmarks item="bookmark"}
    <p>{$bookmark.title}</p>
    <ul>
    {foreach from=$bookmark.comments item="comment"}
        <li>{$comment.description|default:''}(id:{$comment.title})</li>
    {/foreach}
    </ul>
{/foreach}

上記テンプレートから若干書き換えた後のものですが、実際に動作させてみた画面は以下の通り。

こんな風に、外部API同士を組み合わせたサーバサイドのマッシュアップが非常に簡単にできるのがBEARの強みだと思います。

もちろん内部リソースとも全く同じ形で組み合わせる事ができるので、外部APIから何かしら情報を取ってきて、それに内部リソースをリンクして付加価値を付けて、Webアプリケーションとして公開…なんて事がお手軽にできそうですね!

次回は?

BEARはフォーム関連の機能は、PEAR::QuickFormが使われているんですが、QuickFormは使った事がなくてあまりよく分かっていないので、次回から何回かはフォーム関連の機能について学習していきたいと思います。

余談

今回、元々は"最新はてブられコメント一覧"が欲しいと思って、はてブを題材にして、その過程で色々調べてて知ったんですが、はてブの特定URL以下のページの最新ブックマーク一覧って、"http://b.hatena.ne.jp/bookmarklist/?url=〜"で取れるんですね。

記事の中で挙げたentrylistだとソート基準が、"今まで1件もブックマークされていないページが初めてブックマークされた日時"になるようで、古いページにブックマークが付けられてもなかなか気付けなかったんですが、これで、はてブられ状況をリアルタイムで追う事ができそうです。

"あわせて読みたい返信メール"表示機能を付けてみた

少しずつ遊んで下さる方が増えてきているようで、嬉しい限りでございます。m(_ _)m

はてブのコメントで、「むしろ、お祈り返信メールメーカーが欲しい(皮肉たっぷりな感じの)」と頂きまして、「お祈りメールばっかり見せられても、確かに気が滅入っちゃうばっかりだよね」と思い、皮肉のこもった返信メールのサンプルも表示するようにしてみました。

こちらは、以下のスレまとめサイトから本文を拾ってきて、ランダムでどれかを表示させているだけです。

文章は基本的にそのまま使っていますが、改行位置の調整とか、文章内の会社名とか大学名なんかの固有名詞が入る箇所を記号に差し替えたりしています。

最初はこれも自動生成するようなものにしようと思ったんですが、上記スレを見ると返信メールの内容がどれも秀逸過ぎて、このままの方がネタとして面白いだろうという判断で、そのまま使う事にしました。

それにしても、上記スレの中にもありましたが、これだけの文章を作れるセンスがあれば、余裕で内定もらえてるんじゃなかろうかと。(笑)

ちなみに、内容は完全にネタなので、くれぐれも本当にお祈りメールに返信するのに使わないで下さいね。(笑)

BEARで始めるWebアプリケーション開発 その7「複数のリソースからデータを取得して画面に表示する」

今回は、前回作成したリソースを使って、"逆さ語"の画面に"最近変換した文章"を表示させてみます。

ページに表示するリソースを定義する

と言ってもそんなに難しくもなく、以前作成したページのonInitメソッドにちょこっと追加するだけになります。

<?php
    /**
     * 初期化
     *
     * @return void
     */
    public function onInit(array $args)
    {
        // 文章が与えられていたらsentencesリソースに書き込む
        if ( isset($args['s']) === true ) {
            $values = array('s' => $args['s']);
            $params = array(
                            'uri' => 'sentences',
                            'values' => $values,
                            'options' => array(),
                           );
            $this->_resource->create($params);
        }

        // sentencesリソースから最近変換した文章のリストを取得する
        $params = array('uri' => 'sentences');
        $this->_resource->read($params)->set('history');

        // 文章の変換結果を取得する
        $uri = 'sentence';
        $sentence = ( isset($args['s']) ? $args['s']
                      : 'これはサンプルです' );
        $values = array('s' => $sentence);
        $params = array(
                        'uri' => $uri,
                        'values' => $values,
                        'options' => array(),
                       );
        $this->_resource->read($params)->set('preview');
        $this->set('sentence', $sentence);
    }
?>

"ちょこっと"と言いながら、何だかいっぱい増えてしまってますが…。

最初のブロックでは、文章が与えられてページが呼ばれた場合に、文章変換の履歴として、sentencesリソースに書き込んでいます。

真ん中のブロックでは、sentencesにGETリクエストを投げて、最近変換した文章のリストを取得しています。

最後のブロックは以前のまま変更はありません。

これでテンプレートの$historyに最近変換した文章がアサインされるので、後はテンプレート側で適当に見た目を整えてやればオッケーですね。

BEARではリソースに対して、HTTPでアクセスするのと同じ感覚でアクセスできるので、ページからアクセスする場合は、このように必要なリソースアクセスを順番に並べていく感じになります。

今回は利用したリソースが同じアプリ内のものだけでしたが、ここに例えば外部URLのRSSフィードを追加したり、都道府県一覧を定義してあるCSVを読み込んで使ったり、というように、様々な情報を"リソース"という形で簡単に追加していけるという事が分かって頂けるのではないかと思います。

これはかなり強力な仕組みで、例えば「ブログサイトを作ろう」という事で、メインとなる記事の表示・投稿機能なんかをリソースとして作った後に、「コメント機能を追加しよう」とか「ブログパーツを入れよう」とか「twitterの関連つぶやきを載せたいな」とか仕様が増えても、後から非常に簡単に機能を追加する事ができます。*1

これに更に"リンク"の機能を使うと、リソース同士を組み合わせて付加価値を付けた情報を取得したりなんて事ができるようになるので、更にできる事の幅が広がるようになります。

次回は?

という事で、次回は、リソース同士の関連付けを定義する、"リンク"について学習したいと思います。

*1:この辺り、MVCCakePHPとかだと、どういう設計・実装になるのかな…? MVCフレームワークで大きな規模の開発をした事がないので、素朴な疑問です…。

お祈りメールの文面を自動生成するWebサービスを作ってみた

今までに無く"誰得"感を醸し出していますが…まぁ、「思い付いたら作ってみよう」の精神で…。

お祈りメールメーカー

これは何?

俗に言う、お祈りメールの文面をマルコフ連鎖によって自動生成するサービスです。

生成された文章をDBに保存したりはしていないので、面白い文面ができて残しておきたい場合は、コピペしておくか画面キャプチャしておく事をオススメします。

なお、採用担当の方が、このサービスを使ってお祈りメールの文面を作る事はオススメしません。(笑)

実装について

動作としては、お祈りメールの文章からマルコフ連鎖用のテーブルを事前に作っておいて、それを元に文章を組み立てているだけです。

メール文面の元となる文章は、以下のサイトから拾ってきました。

通算300社以上から不採用をうけた人間が不採用メールを貼るスレ【働くモノニュース : 人生VIP職人ブログwww】

マルコフ連鎖部分の実装は、以前試してみた時のものを流用しています。

以前試してみた時は、2単語の組み合わせから次の単語の候補を決めるようにしていましたが、それでやってみると、文章が結構カオスな感じになってしまう事が多かったので、今回は、3単語の組み合わせから次の単語の候補を決めるようにしてみました。

なので、パッと見は比較的さらっと読み流せる文章になっている事が多いですが、よく読んでみると時々めちゃくちゃな事を言っている時があって、結構笑えます。

ただ、マルコフ連鎖の性質上、生成される文章の長さがバラバラなので、冒頭の挨拶だけで終わってしまう場合もあれば、すごいだらだらと同じような文章が続いてしまう場合もあります。

短くなってしまうのはどうしようもないので、長くなる方は、一定数だけ"。"が出てきたら打ち切るようにして、対処しています。

ちなみに、今回は入力フォームも画面遷移も無い、極めてシンプルなWebサービスなのでフレームワークを使うまでもないんですが、練習も兼ねてBEARを使っています。

こんなシンプルなものでもフレームワークを使って作っておくと、後々機能を拡張しようとした時に楽でいいですね。BEARの場合は特に機能拡張し易いので、その辺りは大変重宝しますね。


そんな訳で、遊んでみてもらえる事をお祈り申し上げます。

敬具

追記(2010/02/22)

コメントで、"「末筆ながら」で始まる段落で終わらせるともっとそれらしげになると思います。"と頂いていた点について、こっそり導入してみました。

実際には、文章生成中の終了条件を、生成された文章に対する正規表現で指定できるようにして、"末筆"で始まって"。"で終わる場合に終了するようにしてみました。

これで若干はきれいに終わる場合が多くなったとは思いますが、元々文章の内容を考慮した文章生成ではないので、カオスな文になる事が多いのはある程度はやむを得ないところですね…。