ホーム > アーカイブ > 2010-10

2010-10

CakePHP 1.3で大量のクエリを投げるときの注意点

cakephp_query_shell.png

今日は簡単な記事です。
自分がハマったので、他の人がハマらないように情報共有を。

CakePHPネタで、特にシェルを使っている人向けの記事です。
興味がない方はスルーしてください。

CakePHPで大量のクエリを投げる

CakePHPで、データベースに対して大量のクエリを投げたことがありますか?
お知らせメールでは、シェルもCakePHPで書いています。
そのため、一度の実行で大量のクエリが発行されることがあります。

クエリといっても、CakePHPのラッパーのModel::find()Model::save()のことです。
これをレコード分繰り返すことがあります。
この場合、一回の実行あたりのクエリ発行数は数千から数万に。

このような処理を書いていると、どうもおかしな現象に出くわします。

Warning: SQL Error: 1054: Unknown column 'ComicAuthorMergeQueue.base_id' in 'where clause' in /usr/lib/cakephp1.3/cake/libs/model/datasources/dbo_source.php on line 673
Query: SELECT `SearchIndex`.`id`, `SearchIndex`.`search_index` FROM `search_indices` AS `SearchIndex`   WHERE `ComicAuthorMergeQueue`.`base_id` = 6899

ん…こんなクエリ発行した覚えはないんだけど?

初めはモデル周りの参照の関係が原因だと考えました。
しかし、実はもっと根が深い問題で、CakePHPのキャッシュが絡んでいました。

CakePHPがWHEREをキャッシュしている

CakePHPはデフォルトでWHERE文をキャッシュしています
例として、Model::find()を取り上げます。

$params = array(
	'conditions' => array('id = ' => 1000));
$this->User->find('all', $params);
SELECT * FROM `users` AS `User` WHERE `User`.`id` = 1000;

この”‘conditions’ => array(‘id = ‘ => 1000)“と”WHERE `User`.`id` = 1000“の対応関係をキャッシュするのです。
キャッシュする場所はインスタンスのプロパティ。つまりメモリキャッシュです。
そのため、二度目に同じ条件のModel::find()を呼んだ場合、SQLは動的に生成されません。
メモリキャッシュからWHERE文を取り出し、そのまま使用します。

/**
 * Returns a quoted name of $data for use in an SQL statement.
 * Strips fields out of SQL functions before quoting.
 *
 * @param string $data
 * @return string SQL field
 * @access public
 */
  function name($data) {
    if (is_object($data) && isset($data->type)) {
      return $data->value;
    }
    if ($data === '*') {
      return '*';
    }
    if (is_array($data)) {
      foreach ($data as $i => $dataItem) {
        $data[$i] = $this->name($dataItem);
      }
      return $data;
    }
    $cacheKey = crc32($this->startQuote.$data.$this->endQuote);
    if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) {
      return $return;
    }
/**
 * Cache a value into the methodCaches.  Will respect the value of DboSource::$cacheMethods.
 * Will retrieve a value from the cache if $value is null.
 *
 * If caching is disabled and a write is attempted, the $value will be returned.
 * A read will either return the value or null.
 *
 * @param string $method Name of the method being cached.
 * @param string $key The keyname for the cache operation.
 * @param mixed $value The value to cache into memory.
 * @return mixed Either null on failure, or the value if its set.
 */
  function cacheMethod($method, $key, $value = null) {
    if ($this->cacheMethods === false) {
      return $value;
    }
    if ($value === null) {
      return (isset($this->methodCache[$method][$key])) ? $this->methodCache[$method][$key] : null;
    }
    return $this->methodCache[$method][$key] = $value;
  }

ちょっと省略していますが、このコードがそのキャッシュに当たる部分です。
詳しく調べたい方はdbo_source.phpのDboSource::cacheMethod()を追ってください。

ここで見て分かる通り、crc32()を使ってハッシュを管理しています
実はこのcrc32()を使ったハッシュは数万件のデータで衝突が発生するようです。

衝突が起こると、まったく無関係のWHERE文がModel::find()やModel::save()に対して呼ばれます
その結果が冒頭のエラーです。

キャッシュをオフにする

この現象を突き止めるまでは色々と調べて回りました。
この情報に辿りつくまでに半日ぐらい掛かりました。

CakePHPのチケットです。
このチケットには、こうあります。

I think documentation is a good approach. Fully unique hashes can be slower than crc32 which is why it was chosen. Disabling the cache when its not helpful and providing good documentation on how to do that is probably more pertinent.

#870 Issues with DboSource::$methodCache – CakePHP – cakephpより

これに従って修正されたAPIドキュメントがこれです。

Caches result from query parsing operations. Cached results for both DboSource::name() and DboSource::conditions() will be stored here. Method caching uses `crc32()` which is fast but can collisions more easily than other hashing algorithms. If you have problems with collisions, set DboSource::$cacheMethods to false.

Commit e023350af57e07ac3351ab86c07361697fc1b369 to cakephp’s cakephp – GitHubより

なるほど。
DboSourceクラスcacheMethodsプロパティをfalseに設定すれば良いみたいです。
そうすれば、このキャッシュはオフになると。

余談ですが、CakePHP側ではこの部分の衝突を問題にしていないようですね。
パフォーマンスの問題と、使用方法を天秤にかけたのでしょう。
CakePHPはWebフレームワークで、シェルの重たい処理なんて想定してないでしょうから。

シェルでこのキャッシュ機能をオフにするために、AppShellクラスを作ります。

<?php
App::import('Shell', 'Shell');

class AppShell extends Shell {
  var $cacheMethods = false;

  function initialize() {
    $db =& ConnectionManager::getDataSource('default');
    $db->cacheMethods = $this->cacheMethods;
    parent::initialize();
  }
}

あとは、これを各シェルのクラスが継承すればOKです。

<?php
App::import('Shell', 'AppShell');

class EggShell extends AppShell {
}

キャッシュをオンにしたいシェルがある場合は、こう書きます。

<?php
App::import('Shell', 'AppShell');

class EggShell extends AppShell {
  var $cacheMethods = true;
}

これでOKです。
ここではシェルクラスにAppShellを継承させる形で解決しましたが、これはCakePHP 1.3.x限定です。
CakePHP 1.2.xではシェルクラスに自分で作ったクラスを継承させることができません(厳密に言えばできるのですが、色々と動かなくなるのでそれの対処が面倒くさい)。

ちなみに、この内容はPHP MatsuriのJIREI Nightで話した内容です。

JIREI NIGHT お知らせメール

もし、同じ現象でハマった場合は試してみてください。

Google日本語入力のイベントに行ってきた – コンセプト編

google_ime_logo.png

先週の土曜日、Google 日本語入力 TechTalk 2010に参加してきました。

Google日本語入力を使ったこともインストールしたこともないのに、イベント情報を見た瞬間に参加することを決定。
面白半分で参加することに決めました。

しかし、このイベントは予想外に面白いものでした。
Google日本語入力プロジェクトの立ち上げや、そのコンセプト、さらにはコードリーディングまで。

残念ながら私は技術力も頭も足りないので、詳しく理解できなかった点がたくさんあります。
ですが、有益な情報は共有したいので、記事にまとめてみます。

長くなってしまうので、2部に分けます。
今回はコンセプト編!

Google日本語入力のイベント

このイベントの参加案内があったのは2010年9月17日。
場所は六本木のGoogle東京オフィス14:00-19:00のなかなか長丁場。
懇親会という名の”タダ飯付き“というイベントです。

実際に当日行ってみると、綺麗なホールに約100名以上のエンジニアが集まるという規模の大きさ。
そして、入り口にはなんとお酒があるというおもてなし。
さすがGoogle様、分かってらっしゃる。

オープニングトークで、以下の内容でセッションが行われることが発表されました。

  • Google 日本語入力ができるまで
    • Google日本語入力のコンセプトやプロジェクトの立ち上げについて。配られた冊子を見れば、ほとんどわかる。
  • Google 日本語入力の設計概要
    • Google日本語入力の設計について。既存のIMEと異なる点を取り上げる。
  • Mozc ソースコードレビュー
    • Mozcのソースコードを読む上ためのポイントを説明。ソースを晒しながら、改造するのに必要な点なども。
  • ライトニングトーク
    • IMEに限らず、”入力”というテーマでレベルの高いLTを参加者とGoogle社員が。

順を追って”Google日本語入力“が理解できるようです。
ワクワクしてきました。
(決して、お酒が入ったからではないですよ:P)

Google日本語入力ができるまで

Google日本語入力が出来るまで“は会場で配られたこの冊子を読むとわかります。

google_ime_book.JPG

中は漫画になっています。

google_ime_comic.JPG

わかりやすいので、皆さんに見てもらいたい。
どこかに公開していないのかな?

と思ったらありました。

これを読んでしまえば、この記事もいらn(ry

20%ルール

Google日本語入力は、皆さんお馴染みの”20%ルール“を使って立ち上げられたプロジェクトです。
20%ルールの簡単な説明と、それを使って立ち上げられたプロジェクトが紹介されます。
あの”Google App Engine“も20%ルールで作られたプロジェクトだと、このセッションで知りました。

続いて、このプロジェクトを立ち上げた開発者が紹介されます。

  • 工藤 拓さん
    • 言わずと知れたmecabの開発者。Googleではもしかして検索を担当しているそうです。
  • 小松 弘幸さん
    • 予測変換システム「PRIME」の開発者。工藤さんから声が掛かる前から、Google日本語入力のアイディアを温めていたそうです。

MeCabの開発者”工藤 拓“さんが開発に携わっていたんですね。
そして、Googleに居るというのもびっくり。
まったく予習していないのがバレバレですが…。

リリースまでのプロセス

リリースまでは以下のプロセスで開発を進めたそうです。

  1. ディスカッション
  2. 開発・テスト
  3. ドックフード
  4. 開発版リリース
  5. ベータ版リリース

どれもこれも興味深い話ばかりでした。
特に印象に残ったのは”ディスカッション“と”テスト“、それに”ドックフード“です。

ディスカッション

Google日本語入力をどんなものにするか“を20%ルールを使い、話し合ったそうです。
初めの段階でこういった話をするのは珍しい話じゃない、というか当たり前です。
走る前に考えましょう。

普通じゃないのがこの期間。
約半年“の間、ディスカッションだけに20%ルールの時間を使ったそうで。

その中身は、以下の内容。

  • 既存のIMEの成功/失敗事例
    • 既存のIMEの悪いところや良いところに関して話し合っていく。Google日本語入力のイメージを固める作業でもあったようです。
  • Google日本語入力のコンセプト
    • “どんなIMEを作りたいか”を事例を踏まえ、コンセプトとして固めます。Google日本語入力のコンセプトは”As you think of・空気のように”です。

こういったコンセプトを詰めるのに半年も使うんですね。

6ヶ月 x 4週 x 8時間 = 192時間

約200時間を費やして決めたコンセプト。
優秀なプログラマはコーディングする時間よりも、考える時間の方が長い。
その最たる例な気もします。

テスト

テストで興味深かったのは、以下の3点です。

  • ユニットテスト
  • 変換率と当たり前の変換テスト
  • UIのテスト

Google日本語入力ではしっかりユニットテストが行われています。
これは当たり前なので、特筆すべき点はありません。

面白かったのは”変換率と当たり前の変換テスト“です。
日本語変換という性質上、変換のために”学習型のアルゴリズム“を使います。
この変換はこのアルゴリズムを使って機械的に変換するため、その部分のテストが難しいです。
そこでGoogle日本語入力では、”変換率“のテストの他に、”当たり前の変換テスト“を行っているそうです。

これは何か。
ユーザビリティのテストに当たるもので、”ユーザが欲しい変換“が出来るかどうかをテストするものです。
例えば、”あいます”と入れれば”アイマス”ではなく”会います”が出てくる。
“どこいく”といれれば”ドコイク”ではなく”どこ行く”が出てくる。
こういった具合です。

このような辞書をテスト用に作成し、このテストが全て通らないと出荷しないそうです
テストとその自動化に徹底していますね。

このセッションの最後に、

インターフェースなどのテストの難しい部分はどうしているか?

という質問がありました。
これに対する答えは、

我々もそのベストプラクティスを探している。しかし、できるだけユニットテストに落としこむことが重要。

というものでした。
Googleでもやはり、テストの王道に従い、ユニットテストを積み重ねることで品質を保っているんですね。
どれだけパーツを独立した設計にできるか。
それが重要ですね。

ドックフード

Google日本語入力のイベントに参加するまで、この言葉も知りませんでした。

自分で自分の作ったドックフードを食ってから出せ。
最低限、食べられるモノが出来てから出せ“といった意味が込められています。

Googleでもそれに乗っ取って開発とテストを進めています。
毎日ビルドし、それを社内版として公開しているそうです。
そうして、社内の人間に使ってもらい、フィードバックを得る。

これって基本だと思いますが、とても大事なことですよね。
これを怠った会社はもはやソフトウェア会社じゃないような。
自分で作ったモノが使いにくいのに、誰が使ってくれるんでしょうか。

自分への戒めとしたいですね。

今回の記事はこんなところで。
次回は”Google日本語入力の設計“に関してまとめます。
細かいところまでは理解できなかったので、表面だけさらっと…(苦笑)

他の参加者の方のまとめもどうぞ!

[書評] これを読めばCakePHPに再度惚れられる?CakePHP辞典

cake_php_dictionary.jpg

Bakerの皆さんはCakePHPの魅力は十分に分かっているでしょう。

しっかりとした規約十分にラップされたデータベース周りのロジック
様々な環境に簡単にデプロイ出来るPHPの強みPHPの手軽さ

私自身、CakePHPを使い始めて2年目になります。
2年もCakePHPのコードばかりを書いていれば、CakePHPのうまみを全て味わい尽くしたようにも思えます。

しかし、それを見事に”CakePHP辞典”が打ち崩してくれました。
書店で手に取り、目次を読んだ時点でCakePHPの魅力や楽しさが蘇ってきました
CakePHPにはまだまだ知らない深みがあると。

CakePHP辞典とは

CakePHP向けの携帯サイト構築用ライブラリ”KtaiLibrary“を作成している@ecworks_masapさんこと滝下真玄さんが書かれた本です。

帯には以下のように書かれています。

随一の圧倒的な情報量!
フレームワークの新しい使い方が、必ず見つかる本!

え、誇大広告過ぎやしないか?とも思えるこの謳い文句。

そう思っても、騙されたと思って手に取ってみてください。
始めの1分で謳い文句通り”フレームワークの新しい使い方“が見つかります。

私がそうでした。
滝下さんに買いますね!書評書きますね!“と言っておきながら、実は買うかどうか迷っていた(苦笑)
そこで、書店に行って実際に内容を見てみることにしました。
行ったのは”有林堂 戸塚駅前支店”(自宅がこの周辺なのでよく現れます)。
こんなところにも、ちゃんと置いてありました。
それで、ぱっと目次を開いた瞬間…これは買いだな、と。
そんな本です。

API代わりに使う

それで、なぜ”ぱっと開いた瞬間に買うことが決まる“のか。
それは目次の情報量に秘密があります。

ちょっと失礼して、目次を引用してみます。
(ページ番号は省略しています)

モデルクラス
バリデーション
アソシエーション
AppModelクラス
Modelクラス・プロパティ
Modelクラス・メソッド
Model::find() データソースからデータを検索して入手
Model::findBy() 指定フィールドを条件付けて検索
Model::bindModel() アソシエーション設定を動的に行う
Model::unbindModel() アソシエーションを動的に解除する
Model::setSource() 指定したテーブルでモデルのセッティングを行う
Model::set 値をセット
Model::deconstruct() 日時データを指定フィールドが認識できる日時形式に加工
Model::schema() スキーマを入手
Model::getColumnType() 指定カラムのデータ形式を入手
Model::getColumnTypes() 各カラムのデータ形式をまとめて入手

滝下真玄著 – CakePHP辞典より

えー、書ききれませんね。
これは”モデル”の目次の3分の1も書けていません

こんな目次が始めの21ページに渡り、書かれています。
ぱっと見で機能がわかる目次“がこの本の大きな魅力の一つだと思います。

この情報は普段ならCakePHPのAPIドキュメントから探します。

しかし、このドキュメントは英語である上に、説明がある程度までしか書かれていません
さらにサンプルコードも少ない。

単純に比較する訳にはいかないのですが、APIドキュメントは下記のリンクの”Model::find()“の説明を見てください。

これに対して、”CakePHP辞典”にはここまで説明があります(引用するのはModel:find()の説明の一部だけです)。

$typeに設定する値

  • all : 条件に合致するすべてのデータを取り出します
  • first : 最初に見つかったデータのみを取り出します
  • list : 指定したフィールドのデータをリスト化して取り出します。指定フィールドが1つの場合は、idをキーとする連想配列で取り出します。指定フィールドが2つの場合は「1番目 => 2番目」の連想配列で取り出します。フィールドが無指定の場合はidを配列で取り出します。
  • threaded : 通常は自分のレコードとアソシエーションモデルのレコードを1レコード値として受け取ることができますが、threadedを指定すると、そのレコードの親子関係を解析し、子レコードを階層で取得することができます。このレコード内にさらにこのレコードが存在する場合も再帰的に取得します。この機能を使う場合は「parent_id」という名前のフィールドが必要になります(ほかの名前に変更することはできません)
  • neighbors : find(‘first’)と似ていますが、これは該当レコードの隣り合ったレコードの情報を取得できます。連想配列で「prev」キーの値は該当レコードの値の前のレコード、「next」には後のレコードが格納されます。

滝下真玄著 – CakePHP辞典より

このように、”この辞典一冊で特定のメソッドの使い方がわかる“というのが魅力の二つ目です。

そしてこの二つの魅力が合わさることで、あなたは(少なくとも私は)CakePHPに再度惚れてしまうでしょう

例えば、私は普段使わない”SecurityComponent“に地味に使える機能があることに気がつきました。

Securityコンポーネント
SecurityComponentのクラス・プロパティ
SecurityComponentのクラス・メソッド
SecurityComponent::requirePost() POST形式のリクエストを必要とするアクションを指定
SecurityComponent::requireGet() GET形式のリクエストを必要とするアクションを指定
SecurityComponent::requirePut() PUT形式のリクエストを必要とするアクションを指定
SecurityComponent::requireDelete() DELETE形式のリクエストを必要とするアクションを指定

SecurityComponent::blackHole() 不正なリクエストに対して行う処理を指定する

滝下真玄著 – CakePHP辞典より

POST、GETなどの形式を制限することが出来るんですね!
さらに”SecurityComponent::blackHole()”というコールバックメソッドまで。
うまく使えば、いつも自分で書いているあんなことやこんなことが簡単に…。

皆さんに知っていてもらいたいのは”Set“クラスですね。
CakePHPは基本的にデータを配列で扱います。
そのため、コードの大半が配列処理で埋まります。
この世話を色々としてくれるのがこの”Set“クラス。
もちろんSetクラスも”CakePHP辞典”に載っていますよ。

と、あまり詳しく書いたり、引用すると滝下さんに怒られてしまいそうです(笑)
あとは、本を読んで勉強してくださいね。

便利なtipsを知る

先ほど紹介した辞典的な使い方も良いのですが、ちょっとしたtipsもCakePHP辞典には載っています。
これは良いな“と思ったのが、30ページにある”開発環境と本番環境でのコードの共通化“というtips。
(コメントは省略しています)

class DATABASE_CONFIG {

  var $default;

  var $default_pub = array(
  );

  var $default_dev = array(
  );

  function DATABASE_CONFIG(){
    if($_SERVER['SERVER_ADDR'] == '12.34.56.78'){
      $this->default = $this->default_pub;
    }else{
      $this->default = $this->default_dev;
    }
  }
}

滝下真玄著 – CakePHP辞典より

このようなコードを示したtipsがいくつか載っています。
どれもこれも、すぐに実践で使えるコードです。
これもCakePHP辞典の嬉しいところ。

おまけ、しかし有益な情報

この情報は”資料“として載っているものです。
おまけとして載せたのでしょう。
しかし、とても有益な情報です。

  • CakePHPの定数
    • すぐに忘れるのがこの定数。各ディレクトリのパスなどが格納される定数が一覧化されています。
  • CakePHPの処理の流れ
    • CakePHPの処理が図示されています。コアコード読むのに便利!
  • CakePHPバージョン1.2と1.3の違い
    • 1.2と1.3の差異の概要が分かる。
  • CakePHPに関する情報の入手
    • この情報は初心者にとってとても有益。フレームワークを始めたころは、どこから情報を入手するのかわからないですから。ここを網羅しておけばとりあえず大丈夫でしょう!

あとは最後の索引。
名前は分かるんだけど、どうやって使うんだっけ…“という場合は最後の索引から探してください!
ここにも全てのクラスとメソッドが網羅されてます。

CakePHP辞典はまさに”辞典“と呼ぶに相応しい内容です。
情報へのアクセスのしやすさ、その内容の濃さ。

表現力を高めるために、よく”辞書を読書する“ということが行われます。
小学生のときに先生にやらされた方もいるはず。

フレームワークの表現力を高めるためにも、是非”CakePHP辞典”を読書してください。
CakePHPの魅力に気づき、再度惚れてしまうこと間違いなし。

Pocket詳解 CakePHP辞典 CakePHP辞典

  • 著者: 滝下真玄
  • 出版社: 秀和システム
  • 発売日: 2010/10/01

Pythonの開発環境をperlbrewのように切り替えるpythonbrew

pythonbrew.png

Pythonの勉強をしていて、複数のバージョンで動作をテストしたいことがあったのでメモ。
Pythonのバージョンを簡単に切り替えることができる”pythonbrew“を紹介します。

pythonbrewとは

pythonbrewとはUTAHTAさんが開発したツールです。

上記の記事を読んでもらえれば、pythonbrewとは何者かがわかります。
簡単に言えば、Pythonのバージョンを簡単に切り替えることが出来るツール。

pythonbrew switch Python-2.6.6
pythonbrew switch Python-2.5.5

切り替えはこのコマンドを打つだけです。
簡単ですよね!

素敵なツールをありがとうございます。

インストールする

インストールは簡単です。
ビルドの時間を除けば、5分と掛からずにインストール完了です

curl -LO http://github.com/utahta/pythonbrew/raw/master/pythonbrew # pythonbrewをダウンロード
chmod +x pythonbrew # pythonbrewに実行権限を与える
./pythonbrew install # pythonbrewをインストール
~/python/pythonbrew/bin/pythonbrew init # pythonbrewを初期化
echo "source $HOME/python/pythonbrew/etc/bashrc" >> ~/.bashrc # pythonbrewの読み込みを.bashrcに設定
source ~/.bashrc # .bashrcを再読み込み
pythonbrew install Python-2.5.5 # Python-2.5.5のインストール
pythonbrew install Python-2.6.6 # Python-2.6.6のインストール

詳しくは先ほどの記事を見て頂くとして、これだけでPython-2.5.5とPython-2.6.6の環境が手に入ります
あとは冒頭に書いた”pythonbrew switch“で切り替えるだけ。

こんなに簡単で良いんですかね…。

モジュールをインストールする

pythonbrewでは自動でeasy_installもインストールしてくれます
つまり、PyPIにある外部モジュールも簡単にインストール出来るってこと。

pythonbrew switch Python-2.6.6
easy_install PyYAML

これでPython-2.6.6の環境にYAMLのモジュールが入りました。
簡単過ぎてブログに書くこともありませんね。

スクリプトを組む

これも当たり前ですが、スクリプトでpythonbrewでインストールしたバージョンを使うときは、シェバンを”#!/usr/bin/env python“にします。
#!/usr/bin/python“だとシステムにインストールされたPythonを使ってしまうので。

#!/usr/bin/env python
import sys
print sys.version
# スクリプトが使っているPythonのバージョンが表示される。

ありがたく使わせてもらおうと思います。

ちなみに、Pythonはバージョンによって”正しい書き方“が変わる言語です。
入門書には”このバージョンではこうだった、けどこのバージョンではこうだ。“と書かれていることがよくあります。
Pythonを勉強し始める前にこのpythonbrewを入れると良いかもしれませんね。
ターミナルでのPythonの操作性とこの切り替えのしやすさを組み合わせたら、簡単にコードをテスト出来る

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

このpythonbrewを使って、是非、楽しいPythonライフを送ってくださいな。

TextMateをLinux/Windowsで使いたい人のためのRedcar

redcar-splash.png

プログラマーなら”TextMate“はご存知だと思います。
この”TextMate“があるから、Macを使っているという方もいます。

しかし、このTextMate、”56ドル“もするんです。
(仕事道具なんだから56ドルぐらい出せよ、とも思うけど。)

さらにはLinuxやWindowsには対応していません

今日はその代替えとなる”Redcar“というオープンソースエディタを紹介します。

Redcarとは

先ほど述べた通り、オープンソースのエディタ。
つまり、TextMateとは違い、無料で使えます

トップページに行けば分かると思いますが、クロスプラットフォーム対応です。
Linux/Mac/Windows、どの環境でも使えます。

これがRedcarの魅力の一つ。

また、TextMateのバンドルと互換性があり、これを使うことが出来ます。
あくまで互換性があるだけなので、使えないバンドルもあるようです。

プラグインで拡張も可能です
今、公式のgithubに上がっているプラグインはこれ。

  • Github viewer: View a Github repository in Redcar
  • Go to github: Show current file in github, and selects the same lines that are selected in RedcarEditor
  • GCCSense: highly precise code completion for C/C++, GCCSense required
  • Redcar Debug: Debugger supporting GDB and JDB
  • RSense: highly precise code completion for Ruby
  • redcar-pastie: create a gist from Redcar
  • redcar-help: Displays a help file/user guide for Redcar
  • touchy: Adds a ‘Touch File’ option to the project context menu
  • Code Package View: View directories grouped as packages, for Java, etc
  • Web Bookmarks: View webpages or html files from within redcar

その他にデフォルトでインストールされているプラグイン達。

  • Auto Completer
  • auto_indenter
  • document_search
  • find-in-project
  • HTML View
  • scm
  • scm_git
  • scm_hg
  • scm_svn
  • snippets
  • Strip Trailing Spaces
  • task_manager
  • todo_list

説明は省きますが、昨日のイメージはつきますよね。
色々なことが出来そうです。

しかし、このRedcar、最新バージョンは0.7です。
つまり、まだβ版です。
そのため、日本語でも英語でも情報がとても少ない

このプロジェクトへの応援も兼ねて、MacにおけるRedcarのインストール方法をまとめてみます。
(といってもものすごく簡単ですが。)

Redcarをインストールする

インストールの仕方は、こちらにあります。
手順は簡単で、

  1. RubyGemsでRedcarをインストールする。
  2. RubyGemsにインストールされたRedcarを自分の環境にインストールする。

これだけです。
コマンドを2つ入力するだけで、インストール完了です。

まずは環境チェック。
JavaとRubyのバージョンをチェックします。
Rubyは1.8.7以降、Javaは1.4.0以降が必要だとGetting Startedにあります。

check_the_version.png

バージョンチェックしたら、早速RubyGemsにインストールします。

sudo gem install redcar

gem_install_redcar.png

次は自分の環境にインストール。

redcar install

redcar_install.png

redcar install“を忘れると、起動しないので注意

あとはターミナルからRedcarを起動します。

redcar

running_redcar.png

この記事の始めに使った画像が表示されます。
10秒ほど待つと、エディタが起動。これで準備完了!

main_window_redcar.png

試しにCakePHPのプロジェクトを開いてみました。
デフォルトでPHPのステートメントがカラーリングされます。
良いですね!

open_database_php.png

AppControllerをコーディングしてみました。
これもしっかり、PHPのコードだと認識されていますね。
カッコも自動補完してくれるので、打ち心地もなかなか良い。

create_app_controller.png

Redcarのショートカットをアプリケーションフォルダに作る

ターミナルから起動するのも悪くはないのですが、Macならアプリケーションはアプリケーションフォルダに登録したいですよね。
そこで、アプリケーションフォルダにRedcar起動用のシェルスクリプトを追加します。

cd /Application
vi Redcar

viが開いたら次のコードを書き込みます。

#!/bin/bash
/usr/bin/redcar --ignore-stdin &amp;
exit

後は保存して、実行権限を与えます。

chmod 755 Redcar

これでショートカットが出来ました。
しかし、何かが足りない…そう、アイコンです

今度は作成したRedcarのショートカットから、”情報を見る“を開きます。

redcar_information.png

左上のアイコンは選択出来るんです。
知っていました?

ここに設定したい画像をコピーした上で、ペーストします
画像をコピーする場合は、プレビューを開いて”Command + a“と”Command + c“で可能。

redcar_image_preview.png

これでショートカットにアイコンが設定されました

redcar_in_application_folder.png

ちなみに、私はこのアイコンを使わせて頂きました。

公式のアイコンはここにあるのですが、解像度が低いんです
アイコンが拡大されたときに、画像が荒れてしまうので、私は上記のアイコンを設定しました。

いかがですか?
少し使った感じでは、なかなかキビキビと動いてくれます。
良く使う言語はデフォルトでカラーリングもしてくれますしね。

TextMateのバンドルが使えるかどうか、試してみたのですが、インストール方法が分かりませんでした。
CakePHPバンドルをインストールしたんですが、うまくいかなかった…。

この辺りの情報を持っている方は、教えて頂けると助かります。

引き続き、ちょっと使ってみます。
また機会があれば、ブログにも書きますね。
皆さんも使ってみてください。

開発環境をクリーンにする個人的な3つの禁止事項

desktop.jpg

開発環境は放っておくと自分の部屋と同じで散らかって行きます。
必要なファイルが見つからなくなったり毎日使うツールが壊れてしまったり…

そうなると、仕事が進みません。
PCは唯一の仕事道具なので、出来るだけクリーンに保ちたいもの。

そこで私は個人的に3つの禁止事項を決めています。
今日はそのまとめ。

1. 環境を同居させるな

use_virtual_machine.png

えー、簡単に言うと”仮想化しましょう“ってことです。

Macを使っている方は、Apacheも入ってるし、MySQLもインストール出来るし、そのままでも良いじゃない。

あるいはXAMPPやMAMPを使っている方は、インストールすれば環境が揃うし。

そう思われるかもしれません。

しかし、仮想化して開発用のOSを別に持っておけば、良いことが色々とあります。

  • 環境を壊せる!
    • 好き勝手出来るマシンが1台手に入ったも同然です。自分のマシンでは出来ない恐ろしいことも出来ます
  • 色んなOSが試せる!
    • Debian、CentOS、Ubuntu、FedraやWindowsまで。何でも入れ放題です。試してみたいときはCDをマウントしてすぐさまインストールです。

Linuxに慣れていないユーザは、純粋に”Linuxに触れられる“というのもメリットですよ。
私自身、仮想化して自分の環境にLinuxを持つようになってから、かなり詳しくなりました。

これも、何度も無謀なことをしてLinuxを再インストールした結果ですね。
(さようなら、そしてありがとう。私の犠牲となったLinux達。)

仮想化の環境も簡単に手に入ります。
VMware Server“や”VirtualBox“といったキーワードで検索してみて下さい。
情報がたくさん見つかるはずです。

Macユーザなら”VMware Fusion“も良いかもしれません。

VMware Fusion 3 VMware Fusion 3

  • 対応OS: MacOS X 10.5.8以降
  • 販売: act2
  • 発売日: 2009/11/06

開発環境を仮想化して、別に持つことで、”環境を壊す恐怖“から解放されます。

2. フォルダを使うな

do_not_use_folders.png

私はドキュメントを管理するのにフォルダを使いません
完全に言い切ってしまうと嘘ですね。

出来るだけフォルダを使わないようにしています。
使っているフォルダはこれだけ。

  • files
    • 画像やワード、圧縮したファイル類全てこの中に。
  • download
    • Webからダウンロードしたファイルはこの中に。必要なファイルだけfilesに移す。この中で1ヶ月アクセスがないファイルは自動的に削除。
  • workspace
    • 作業中のプロジェクトはこの中に。中ではプロジェクト毎にフォルダ管理する。プロジェクトが終了したら圧縮してfilesフォルダに移動。

フォルダはこれだけですが、個人的には十分です。
filesの中身が分かりにくくなる?
それはこんな感じに管理することで解決しています。

finder_files.png

そう、野口さんの”「超」整理法“方式です。
これなら考えずに、フォルダの中にデータを突っ込んで行けます
探すときは”Spotlightで検索をする“か、各アプリケーションの”最近使ったファイル“を使いましょう。

これで、ファイルをどこに入れるか、考えずに済みます。
頭の中もすっきり。

有名な本ですが、”「超」整理法“を読んだことがない方は是非。
ちょっと古いですが、デジタルにも応用が効く良い内容ですよ。

「超」整理法―情報検索と発想の新システム (中公新書)
a>
「超」整理法―情報検索と発想の新システム (中公新書)

  • 著者: 野口 悠紀雄
  • 出版社: 中央公論社
  • 発売日: 1993/11

3. ブックマークを使うな

do_not_use_stars.png

ブラウザのブックマークは使いません
それは、ブックマークが溢れ返ってしまうから。

皆さんも経験ありませんか?
ブックマークが溢れ返り、自分の欲しい情報に辿りつけないストレス

私もこれにしばらく悩まされていました。

“あー、あれどこだっけ、えーっと…”
“あぁ、あった!programsフォルダの中か。なんでここに入ってるんだ。”
“(見つけたブックマークを開く)うわ、リンク切れ!”

これ、最悪のパターンです。
苦労して見つけた結果が、リンク切れ
もう、嫌になりません?

このストレスが嫌で、ブックマークを一切使わないことにしました
頼るのはGoogleEvernote

大概、記憶の断片としてキーワードは残ってるんですよね。
普段から使うページはサービスの名前やURLを覚えてたりする。

だから、こんな感じで分けてやるんです。

  • 良く使うサービス → Chromeのアドレスバーで”キーワードかURL”から検索
  • 開発のヒントになる情報 → Evernoteにクリップしておいて、後からEvernoteクライアントで検索

この二つだけあれば、ブックマークなんて無用。
さっさと、ブックマークの管理なんて止めちゃいましょう。

ブックマークを諦めることで、情報を探し回るストレスから解放されますよ。

これが自分に戒めている3つの禁止事項です。
どれもこれも、ちょっとしたストレスを感じて、改善してきた結果です。
皆さんには皆さんのやり方があると思います。
それに、私もまた改善するかもしれませんしね。

しかし、記事に書いたストレスを少しでも感じたら、記事を参考にやり方を変えてみてください。
これは必要だろう!と思っていることを投げ捨てれば、新しい世界が開けますよ

“初めてのPython”を、1週間で攻略する6つのポイント

calender_python.jpg

以前に”Pythonの勉強をまったく始められないあなたと私に送る8つのタスク“という記事を書きました。

この記事を覚えていますか?
皆さん、この通りにタスクを消化出来ているでしょうか

自分で目標を立てておいて申し訳ないのですが、自分はステップ1で早速遅れが生じました
初めてのPython“はなかなか手強く、このタスクを消化するのに2週間を使ってしまいました。

そもそも、この”初めてのPython“に挫折した人も多いはず。
前回の記事についたはてブのコメントを見てそれを感じました。
総ページ数が768、付録を抜いても700ページはあります。

これを2週間で読了するには”作戦”が必要です。

私自身、”初めてのPython“には一度挫折しています。
あの記事を書いたのが2回目の挑戦であり、3度目の正直、ではなく2度目の正直でした。

その経験と、個人的に知っている読書スキルを踏まえて、”1週間で初めてのPythonを攻略する6つのポイント“をまとめてみます。
皆さんは1週間で”初めてのPython“を読めるように。

1. 計画を立てる

まず、計画を立てましょう。
計画とは期限と、その期限を守るためにタスクを分割すること。

実は”初めてのPython“は1週間で読むのに、ちょうど良く構成されています

  1. Pythonの基礎知識
  2. ビルドインオブジェクト
  3. ステートメント
  4. 関数
  5. モジュール
  6. クラスとオブジェクト指向プログラミング
  7. 例外

7部構成になっているんです。
つまり、単純に1日1部読めば良いんです

それぞれボリュームがあります
しかし、それは残り4つのポイントを踏まえれば読める量だと思います。

2. 読まない

速く読む方法、それは”読まない“ことです。
読まなければ、”読む時間“は掛かりませんからね。

とは言え、読まなければ知識は得られません。
そこで、以下の二つを念頭に置きながら読んでいきます

  1. 2回読んで理解出来ない部分は読み飛ばす
  2. コードを中心に理解する

これを実践するだけで読むのは格段に速くなるはず。

2回読んで理解出来ない部分は読み飛ばす

理解出来ない点を読み飛ばすのは不安ですが、2回読んで理解出来ないところは”自分の実力が足りない“か、”理解するのに情報が足りないか“のいずれか。

自分の実力が足りないのは、もうどうしようもありません。
諦めましょう(笑)
そのうち理解出来るようになります。

理解するのに情報が足りないのは、その先を読めば理解出来ます。
本において情報はいくつかの文や段落で成り立ちます。
作者はいくつかの文や段落を通して、1つのことを伝えようとしています。
つまり、理解出来ない部分で悩むのは無駄
どんどん先に進みましょう。
そのうち、理解出来ますよ。きっと。

コードを中心に理解する

Pythonはある意味、”WYSIWYG“な言語です。
つまり、長々と説明されるよりも、コードを見た方が早いことが多いです。
ざっと説明を読み、腹落ちさせるのはコード。
初めてのPython“には分かりやすいコードがたくさん載っています。
 
私自身、こういった読み方で”初めてのPython“を攻略しました。

3. メモをとる

これだけの分量の本です。
ものすごく記憶力の良い方であれば良いのですが、私を含めた凡人には読みながら記憶することは出来ないでしょう
だからこそ、メモを取ります
ポイントを書き出すのではなく、各部毎にまとめたメモを作ります。

私はマインドマップで1部ずつまとめていきました。
雑ですが、これで十分かと。

learning_python_mindmap.png

とにかく時間との勝負なので、ざっと必要なところをまとめます。
あとで見直すので、ページ数もメモすると良いと思います。
私はページ数のメモを忘れて、対象のページを探すのに時間が掛かりました…。
付箋を使うのもありですね!

4. Pythonの中心を把握する

学生時代、教官になんて言われたか覚えていますか?
特に中学かな。

必ず、授業の予習/復習してこいよ。

大人になると、これを忘れがちです。
“Pythonの中心を把握する”というのは、”Pythonを予習する“ってことです。

Pythonの中心、それは

クラスはもちろん、関数やモジュールが全てオブジェクトである。

ということです。
初めてのPython“ではこの話が中心となり、Pythonの説明が書かれています。
これを念頭に置くだけで理解が早まるはずです。

あら、もう予習出来てしまいましたね!

5. 手早く予習する

各部を読んでいくのも、必ず予習します
全体像をつかんでから、読み進めます。
こうすると、自分が必要としているところだけを読むことが出来ます。

予習に使うのは目次1-byte.jpです。
(ブログの宣伝ではないですよ:D)

まず、各部を読む前に”目次“に目を通し、どんなことが書かれているか把握します。
ほう、なるほど。こんなことが書かれているのか。“と。

それが終わったら、1-byte.jpで各部をまとめた記事があるので、それに目を通します。

これだけで十分な気がしてくる?
これは個人的な勉強メモに過ぎません。
それぞれ必要とする情報は違うはず。
あくまで”どんなことが書かれているか”の把握に使ってください。

そして、本当に本当に、本当にあなたが必要な情報を”初めてのPython“から抜き取ってください。

6. 実践する

時間があれば、理解を深めるためにコードを書いてください

部の最後に”まとめの問題集“があるのですが、これは読み飛ばしてOKです。
それよりも、自分でまとめた内容を自分で実践してみてください。
そうすると、理解が間違っていた点が浮き彫りになります。

学習は”トライ & エラー“だと思います。

“実践する”ということはまさにそれで、理解を深めます。
私はブログにまとめる“という方法で、これを実践しました。
ブログにまとめるために、かなり間違ったコードを書きました。

ただ、ここまでやると時間が足りなさそうな、そんな気がします。
ここは、別ステップに分けても良いかもしれませんね

どうですか?
1週間で”初めてのPython“が読める気がしてきましたか?

あれだけ厚い本です。
頭から読もうとしないでください
自分が必要なところだけ読んでしまえば良いんです。
頭から読もうとすると、読む前に心が折れてしまいます

Pythonの勉強をまったく始められないあなたと私に送る8つのタスク“の記事はたくさんの方に読んでもらい、とても嬉しかったです。
あれだけのはてブがついたのも初めてでした。
(実はあの記事のせいで、ブログの更新がちょっと止まってしまったのですが…それは別の話)

タスクとその期限を決めておいて、放置するのも無責任だと思ったので、”初めてのPython“の総括がてら、こんな記事を書いてみました。

Pythonはすごく良い言語だと思います。
一人でも勉強する人が増えれば個人的には嬉しいです。
一緒に勉強出来ますしね。

引き続き、Pythonista目指して頑張りましょう!

初めてのPython 第3版 初めてのPython

  • 著者: Mark Lutz (著), 夏目 大 (翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2009/02/26

CakePHPでメールの送信を簡単にするEmailPlugin

cakephp_email_component.png

CakePHP付属のEmailComponentは使いにくくありませんか?
色々な設定を何度も書かなければいけなかったり、シェルで使うために自分で設定を初期化しなければいけなかったり。

そういった点を解消したプラグインを作ったので紹介します。
しかし、まだ発展途上なのでバグがあったり、機能が足りなかったりするかもしれません。
気長に見守ってやってください:D

EmailPluginとは

先ほど説明した通り、CakePHP付属のEmailComponentを使いやすくしたプラグインです
メールに関する機能を取りまとめたいと思い、EmailPluginと名付けました。

現在、EmailPluginには以下のクラスが含まれています。

  • ExEmailComponent
    • EmailComponentを継承したクラス
  • EmailShell
    • ExEmailComponentをシェルで使うためのクラス

この二つのクラスを使って、メールの送信を簡単に行うことが出来ます。

基本的な使い方はCakePHP付属のEmailComponentと同じなので、CakePHPのマニュアルに目を通しておくと、説明が理解しやすいと思います。

設定を作成する

EmailPluginを使うにあたって、設定ファイルを作る必要があります
CakePHPの設定ファイルであるdatabase.phpに似せて作ってあります。

/path/to/your_app/mailer.php

<?php
class MAILER_CONFIG {
    var $default = array(
        'to' => 'to@test.com',
        'from' => 'from@phpmatsuri.com',
        'replyTo' => 'replayTo@test.com',
        'readReceipt' => 'readReceipt@test.com',
        'cc' => array('cc@test.com'),
        'bcc' => array('bcc@test.com'),
        'subject' => 'This is test.',
        'headers' => array('headers'),
        'additionalParams' => array('additionalParams'),
        'layout' => 'default',
        'template' => 'phpmatsuri',
        'lineLength' => false,
        'sendAs' => 'text',
        'delivery' => 'smtp',
        'charset' => 'utf-8',
        'xMailer' => 'PHP Matsuri Mailer',

        'port' => 25,
        'host' => 'localhost',
        'timeout' => 10,
        'username' => 'test@m.ubuntu',
        'password' => 'test',
        'client' => 'testclient',
    );
}

各設定値はEmailComponentのプロパティと同じです
もちろん、省略も可能です。
設定値の意味合いを知りたい方はCakePHPのAPIを参照ください。

$defaultだけでなく、自分の好きな名前で設定を作ってください。
そうすると、コントローラやシェルから動的に設定値を変更出来ます。

コントローラからメールを送る

コントローラからメールを送るには、“Email.ExEmail”をコンポーネントとして、$useMailerConfigにMAILER_CONFIGに設定した名前をセットするだけです

class MailController extends Controller {

    var $uses = array();

    /* Email.ExEmailをコンポーネントとして定義します。 */
    var $components = array('Email.ExEmail');

    /* MAILER_CONFIGのプロパティの名前を指定してください。 */
    var $useMailerConfig = 'default';

    function index() {
        if(isset($this->params['data']['send'])) {

            /* 設定を動的に変える場合はExEmail::useConfig()を使います。 */
            // $this->ExEmail->useConfig($this->params['data']['setting']);

            /* 各設定を動的に変える場合はEmailComponentと同様にプロパティを変更します。 */
            $this->ExEmail->to = $this->params['data']['to'];
            $this->ExEmail->set('body', $this->params['data']['body']);

			/* 送信はもちろんExEmail::send()を使います。 */
            $this->ExEmail->send();

			/* あとはお好きに処理を書いてください。 */
            $this->set('error', $this->ExEmail->smtpError);
            $this->render('result');
        }
    }
}

シェルからメールを送る

シェルからメールを送る場合もコントローラと同様です
$componentsプロパティを設定する必要がない点が異なります。

また、通常シェルでは指定出来ない$helpersプロパティも指定出来ます。
$helpersプロパティを指定すると、メールのテンプレート中で指定したヘルパーが使用出来るようになります。

言い忘れていましたが、AppShellでなくEmailShellを継承してください
EmailShellを継承しないと、ExEmailComponentを使ってメールが送れません。

/* プラグインからEmailShellを読み込みます。 */
App::import('Shell', 'Email.EmailShell');

/* EmailShellを継承してください。 */
class SendShell extends EmailShell {

    /* MAILER_CONFIGのプロパティの名前を指定してください。 */
    var $useMailerConfig = 'default';

	/* メールのテンプレートで使用するヘルパーを指定してください。 */
    var $helpers = array('Html', 'Time');

    function startup() {
    }

    function main() {

        /* 各設定を動的に変える場合はEmailComponentと同様にプロパティを変更します。 */
        $this->ExEmail->to = 'test@test.com';
        $this->ExEmail->set('body', $this->params['body']);
        $this->ExEmail->send();

		/* あとの処理はご自由にどうぞ。 */
        if(empty($this->ExEmail->smtpError)) {
            $this->out('Complete.');
            return;
        }
        $this->out($this->ExEmail->smtpError);
    }

}

ちょっとした機能

ちょっとした機能も追加されています。

  • 文字コードの自動変換
    • デフォルトのEmailComponentは文字コードを自動で変換しませんが、ExEmailComponentは$charsetプロパティの値を見て自動で文字コードを変換します。
  • 自動改行禁止
    • EmailComponentはRFC2822で推奨される1行 = 70字を守り、自動で改行を入れてくれます。しかし、ここで使われているwordwrap関数はマルチバイトに対応していません。そのため、日本語で送信する場合はこれが文字化けの原因となります。これを防ぐため、自動改行禁止のオプションを追加しました。ExEmailComponentの$lineLengthプロパティにfalseを指定することで自動改行を禁止します。

今後の拡張

今後の拡張として、以下を考えています。

  • 空メール登録機能
  • エラーメール処理機能
  • メールキュー機能

EmailPluginを入れることで、”簡易的なメルマガサーバ“を作ることが出来れば良いな、と。

EmailPluginCakePHP 1.3+専用で、githubで公開しています。

説明文を書いていたら、いつもと違い、堅苦しい文章になってしまいましたorz
まだまだ、発展途上なプラグインです。
将来性を考慮して使って頂ければありがたいですね。

参加していないあなたのためのPHP Matsuri PHP5.3のまとめ(2)

php_matsuri_lithium.png

前回の記事の続きです。

PHP 5.3+専用のフレームワークであるLithiumについて簡単にまとめます。

Lithium

Lithium: The Framework for People Who Hate Frameworks

このセッションでは”Lithium sucks.(Lithiumは最悪!)“という一文が出てきます。
Lithiumの紹介のセッションなのに、Lithiumは”最悪“なんです。

しかし、Nate Abeleさん曰く、問題ないそうで。
それは、

Because your framework sucks, too.(あなたのフレームワークも最悪だからね。)

とのこと。

こういった皮肉まじりのジョークが入り、楽しいセッションでした。
内容は以下の通りに進んで行きます。

  1. なぜ、フレームワークが最悪なのか
  2. 最近のLightweight Languageに適用されているデザインパターンはどうなのか
  3. Lihitumはそれをどう改善したのか
  4. Lithiumではどんなコードが書けるのか

それでは順に見ていきましょう。

なぜ、フレームワークが最悪なのか

フレームワーク利用者は皆思っていること。
それを適切に指摘します。

  • Code you will never use: あなたが使わないだろうコード
  • Complexity overhead: 複雑な処理によるオーバーヘッド
  • You didn’t write it: 自分で書いていないコード

フレームワークを使い始めたころはその便利さに感動します
しかし、この3つの項目はフレームワークを使い続けるにつれて、確かに気になってきます。

その結果、”フレームワークって要らないよね。“という極端な話になったり、ならなかったり。

Nate Abeleさんはコードも交えて説明してくれます。

function spam($emails) {
	$this->Email->replyTo = 'nigerian.prince@example.com';
	$this->Email->from = 'Desmond Etete <nigerian.prince@example.com>';
	$this->Email->template = 'mo_monies';
	$this->Email->sendAs = 'annoying_html';
	foreach ($emails as $email) {
		$this->Email->to = $email['address'];
		$this->Email->subject = 'Good to you news I have {$email['name']}';
		$this->Email->send();
	}
}
// $this->Emailばっかり...。Sucks!

まさにその通り!
これがCakePHPのコードです(この例は大げさだと思いますが)。
そして、フレームワーク利用者が気になるところでもあります

最近のLightweight Languageに適用されているデザインパターンはどうなのか

では、なぜこんなことになるのでしょうか。
それは、Java向けに作られたデザインパターンをLightweight Languageに適用したせいだとNate Abeleさんは言います。

デザインパターンは万能ではない。

つまり、

それぞれのデザインパターンは限られた条件下でその威力を発揮する。

ということです。

lithium_design_pattern.png

Lithiumはそれをどう改善したのか

LithiumではAspect-Oriented Designと言われるデザインパターンを使っています。
日本語ではアスペクト指向デザインと訳されます。


アスペクト指向プログラミング (AOP: Aspect Oriented Programming)は、オブジェクト指向ではうまく分離できない特徴(クラス間を横断 (cross-cutting) するような機能)を「アスペクト」とみなし、アスペクト記述言語をもちいて分離して記述することでプログラムに柔軟性をもたせようとする試み。

アスペクト指向プログラミング – Wikipediaより

例えば、

  • キャッシュ
  • ロギング
  • アクセスコントロール

これらは、処理の中心となるオブジェクトが知る必要がないんです
このようなコードを排除したいのです。

class User {
	public function create() {
		$logger = new Logger();
		$logger->write('Creating a new user...');
		$this->_doSomeInitialization();
		$this->_databaseConnection->doATransaction($this)->create();
		$logger->write('Finished creating user');
	}
}
$user = new User();
$user->create();
// ログを取るのに2回もwriteメソッドを呼ぶ必要がある。しかもcreateメソッドの中で!

確かに、こういった処理はコードを書く上で煩わしいものですよね。
本流の処理とはまったく関係ない処理が、途中に入るためにとてもコードが見づらくなる

さらにこれらの問題を解決するために関数型プログラミングも取り入れています。
これが前回説明した無名関数(lambda式)に繋がります。

これを取り入れることで”参照透過性“を高めることが出来ると言います。

Lithiumでは以下の機能を全てアダプタとして提供しています。

  • Auth
  • Cache
  • Catalog
  • Connections
  • Logger
  • Session

アダプタとして提供されるということは、結びつきが少なくそれぞれのクラスごとにカスタマイズが効くということ
以下のコード例が紹介されます。

use lithium\security\Auth;
Auth::config(
	array(
		'customer' => array(
			'adapter' => 'Form',
			'model' => 'Customer',
			'fields' => array('email', 'password')
		)
	));
use lithium\storage\Cache;
Cache::config(
	array(
		'local' => array('adapter' => 'Apc'),
		'distributed' => array(
			'adapter' => 'Memcached',
			'servers' => array('127.0.0.1', 11211),
		),
		'default' => array('adapter' => 'File')
	));
use lithium\data\Connections;
Connections::config(
	array(
		'old' => array(
			'type' => 'database',
			'adapter' => 'MySql',
			'user' => 'bobby_tables',
			'password' => '******',
			'database' => 'my_app' ),
		'new' => array(
			'type' => 'http',
			'adapter' => 'CouchDb',
			'database' => 'my_app' )
	));

キャッシュを複数環境で運用したい場合は、

use lithium\storage\Cache;
Cache::config(
	array(
		'default' => array(
			'development' => array(
				'adapter' => 'Apc'
			),
			'production' => array(
				'adapter' => 'Memcached',
				'servers' => array('127.0.0.1', 11211)
			)
	)
));

こういった書き方が出来ます。

lithium_adapter1.png

lithium_adapter_2.png

確かにフレキシブルで書きやすそうですね。

Lithiumではどんなコードが書けるのか

コード例がいくつか紹介されます。
まずはキャッシュとロギング。

lithium_caching_and_logging.png

use lithium\analysis\Logger;
Post::applyFilter('find',
	function($self, $params, $chain) {
		// Generate the log message
		$conditions = $params['options']['conditions'];
		$message = 'Post query with constraint ' . var_export($conditions, true);
		Logger::write('info', $message);
		return $chain->next($self, $params, $chain);
	});

次にモデル。

lithium_databases.png

<?php
	$post = Post::create(array(
		'title' => 'Forget the words and sing along',
		'body' => 'Everything you know is wrong' )); $post->save(); $post = Post::find($id);
?>
<h2><?=$post->title; ?></h2>
<p><?=$post->body; ?></p>

最後に外部ライブラリの読み込み。

/* add the trunk */
Libraries::add('Zend', array(
	'prefix' => 'Zend_',
	'includePath' => '/htdocs/libraries/Zend/trunk/library',
	'bootstrap' => 'Loader/Autoloader.php',
	'loader' => array('Zend_Loader_Autoloader', 'autoload'),
	'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; }
));
// Note that 'path' can be dropped if trunk/library/Zend is placed
// directly into your /libraries directory. 

/* add the incubator */
Libraries::add('Zend_Incubator', array(
	'prefix' => 'Zend_',
	'includePath' => '/htdocs/libraries/Zend/incubator/library',
	'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; }
));

簡単ですがLithiumのまとめはここまでです。
Lithiumを使ってアプリケーションを書いたことがないので、理解が浅い部分があります
そのため、Nate Abeleさんの話を簡単にまとめてみました。

もし、Lithiumの情報に日本語でアクセスしたい場合は@yandoさんのブログを見てください。

Lithiumのアップデート毎に翻訳を書いてくれているので、とても参考になります。

内部処理について知りたい場合は、@shin1x1さんがLithiumのフィルタについてまとめてくれています。

また、途中に”Relational databases coming soon“とあるのですが、MySQLのアダプタは公式から出ています。
PostgreSQLのアダプタ@kaz_29さんがPHP Matsuriのハッカソンで開発してくれました。

PHP Matsuriの大きな成果の一つですね。

これからはCakePHPだけでなく、Lithiumも触ってみたいと思います。
ちょくちょくLithiumネタも書いていくので、1-byte.jpもよろしくお願いします。

参加していないあなたのためのPHP Matsuri PHP5.3のまとめ(1)

php53_with_phpmatsuri.png

今日はPHP Matsuriのまとめ第二弾です(前回の記事はこちら)。
PHP Matsruiで行われた以下の2つのセッションをまとめます。

ただし、私は予習なしにこのセッションを聞きました。
(PHP 5.3にあまり興味がなかった…)

そのため、理解が浅いところがあります。
あくまで、”PHP 5.3をまったく知らない人のためのまとめ“として読んでください。

PHP 5.3

Practical PHP 5.3

PHP 5.3にはこれまで長く望まれてきたいくつかの機能が実装されています。
その機能をPHP 5.3+専用のフレームワークLithiumの開発者であるNate Abeleさんが紹介します。

小さな機能追加として、

  • Performance
    • パフォーマンスの向上
  • Syntax
    • シンタックスの変更
  • Phar
    • Pharアーカイブのサポート
  • SPL classes
    • PHP標準のクラスの追加
  • ext/fileinfo
    • fileinfoエクステンションの追加
  • ext/sqlite3
    • sqlite3エクステンションの追加
  • ext/intl
    • 国際化拡張エクステンションの追加
  • mysqld
    • MySQLドライバ変更によるパフォーマンス向上

そして、大きな機能追加として、

  • Late Statig Bindings
  • Lambdas / closures
  • Namespaces

が紹介されます。
小さな機能追加は上記に説明した通り。

以下では大きな機能追加について簡単に説明してみます。

Late Static Bindings

PHPのドキュメントでは”遅延静的束縛“と訳されています。

PHP 5.3以下の”self“の問題点を解決するために導入されたようです。

PHPのドキュメントには以下の例が挙がっています。

selfの使用例

<?php
class A {
		public static function who() {
				echo __CLASS__;
		}
		public static function test() {
				self::who();
		}
}

class B extends A {
		public static function who() {
				echo __CLASS__;
		}
}

// Aが表示される。
B::test();
?>

staticの使用例

<?php
class A {
	public static function who() {
		echo __CLASS__;
	}
	public static function test() {
			static::who();
	}
}

class B extends A {
	public static function who() {
		echo __CLASS__;
	}
}

// Bが表示される。
B::test();
?>

さらに実用的な例はアシアルブログさんのこちらの記事が参考になります。

selfの使用例

<?php
// lsb.php

class User
{
	protected $password;

	public function __construct($password)
	{
		$this->password = self::convertPassword($password);
	}

	public function getPassword()
	{
		return $this->password;
	}

	static public function convertPassword($password)
	{
		return md5($password);
	}
}

class AdminUser extends User
{
	static public function convertPassword($password)
	{
		return sha1($password);
	}
}

$user = new User('password');
var_dump($user->getPassword());
// "5f4dcc3b5aa765d61d8327deb882cf99"が表示される。

$admin = new AdminUser('password');
var_dump($admin->getPassword());
// "5f4dcc3b5aa765d61d8327deb882cf99"が表示される。

staticの使用例

<?php
// lsb.php

class User
{
	protected $password;

	public function __construct($password)
	{
		$this->password = static::convertPassword($password);
	}

	public function getPassword()
	{
		return $this->password;
	}

	static public function convertPassword($password)
	{
		return md5($password);
	}
}

class AdminUser extends User
{
	static public function convertPassword($password)
	{
		return sha1($password);
	}
}

$user = new User('password');
var_dump($user->getPassword());
// "5f4dcc3b5aa765d61d8327deb882cf99"が表示される。

$admin = new AdminUser('password');
var_dump($admin->getPassword());
// "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8"が表示される。

この”Late Static Bindings“を使うことで、静的なクラスがかなり扱いやすくなるようです
こういった特徴を活かし、PHP 5.3+のフレームワークであるLithiumは多くの部分で静的にクラスを扱っています

The Quintessential Blog Tutorialより

<?php
namespace app\controllers;
use app\models\Post;

class PostsController extends \lithium\action\Controller {

    public function index() {
        $posts = Post::all();
        return compact('posts');
    }
    public function add() {
        $success = false;
        if ($this->request->data) {
            $post = Post::create($this->request->data);
            $success = $post->save();
        }
        return compact('success');
    }
}

$thisを使うよりもコードがすっきりして、わかりやすいですね。
もっと、利点があるのでしょうが、まだ詳しくは語れません。
まとめたブログも少ないので、そのうち1-byte.jpでまとめてみたいですね。

Lambdas / closures

PHP 5.3からLambda式が使えるようになりました。
これは名前がない関数を定義出来る機能
PHPのマニュアルでは無名関数として載っています。

以下が最もシンプルな例です。

$function = function($string) { printf("This is function and %s.", $string); }
$function("hoge");

変数として関数を定義して、持ち歩けるイメージですね。
さらに詳しい例はこちらをどうぞ。

後で説明しますが、Lithiumではフィルタとして活用しているようです。

Namespaces

Namespaceはそのまま、名前空間です。

なぜ、名前空間が必要なのかを見てみましょう。


PHP の世界では、名前空間は次のふたつの問題を解決するための手段として用意されています。 ライブラリやアプリケーションの作者が、 クラスや関数といった再利用可能なコード部品を作ろうとするときにこれらの問題にぶちあたることになります。
1. あなたが作成したコードと PHP の組み込みのクラス/関数/定数 あるいはサードパーティのクラス/関数/定数の名前が衝突する
2. 最初の問題を解決するためには、Extra_Long_Names のような長い名前をつけなければならない
PHP の名前空間は、関連するクラスや関数そして定数をひとまとめにして扱うものです。 PHP の名前空間構文の例を見てみましょう。

PHP: 名前空間の概要より

これまでPHPには名前空間が存在しませんでした
そのため、PEARなどのライブラリを使用する場合、そこで使用されているクラスと衝突しないかを考慮する必要がありました。
上記にある通り、これを名前空間が解決してくれます。

// hogeライブラリの空間空間
namespace hoge\lib;

class String() {
	var $var = "";

	function String($var) {
		$this->var = $var;
	}

	function clear() {
		$this->string = "";
	}
}

// barライブラリの名前空間
namespace bar\lib;

class String() {
	var $var = "";

	function String($var) {
		$this->var = $var;
	}

	function set($var) {
		$this->string = $var;
	}
}

// プログラム本体
namespace main;

$hogeString = new \hoge\lib\String('test');
$barString = new \bar\lib\String('test');

$hogeString->clear();
print $hogeString->var;
// 当たり前だが、これはエラー
// $hogeString->set();

$barString->set('');
print $barString->var;
// 当たり前だが、これもエラー
//$barString->clear();

名前空間を利用することで、完全に独立したプログラムが作成出来ますね。
Nate Abeleさんは”始めはこのバックスラッシュが奇妙だけど、慣れると普通になるよ。“と言っていました。

また、PHPにおける名前空間は”PSR-0“で標準化されています。
この”PSR-0″は@hnwさんが和訳してくれています(感謝!)。

PHP 5.3の目玉機能はこんなところです。
ちょっと楽しくなりませんか?
特に他の言語をやっている方にとっては”やっと実装されたか!“という感じでしょうね。

Lithium

Lithium: The Framework for People Who Hate Frameworks

ここでLihitumをまとめようと思ったのですが、長くなってしまったのでここまでにしておきます。

次回はLithiumについてまとめますね!
連載になってしまってすみませんorz

ホーム > アーカイブ > 2010-10

スポンサードリンク
書いている人
つぶやき
RSS 気になるニュース
過去の記事

ページの上部に戻る