<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Born Too Late</title>
	<atom:link href="http://blog.yuyat.jp/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.yuyat.jp</link>
	<description>Yuya&#039;s tech blog.</description>
	<lastBuildDate>Sat, 04 Feb 2012 11:25:32 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>PHP と MySQL でカジュアルに MapReduce する</title>
		<link>http://blog.yuyat.jp/archives/1706</link>
		<comments>http://blog.yuyat.jp/archives/1706#comments</comments>
		<pubDate>Sat, 04 Feb 2012 11:25:32 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[MapReduce]]></category>
		<category><![CDATA[MyMR]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1706</guid>
		<description><![CDATA[副題: ビッグデータ時代の非ビッグデータ集計戦略 PHP と MySQL を使ってカジュアルに MapReduce する MyMR というものを作ってみました. とても安直な名前ですね. yuya-takeyama/my [...]]]></description>
			<content:encoded><![CDATA[<p>副題: ビッグデータ時代の非ビッグデータ集計戦略</p>
<p>PHP と MySQL を使ってカジュアルに MapReduce する MyMR というものを作ってみました.<br />
とても安直な名前ですね.</p>
<p><strong><a href="https://github.com/yuya-takeyama/mymr">yuya-takeyama/mymr &#8211; GitHub</a></strong></p>
<p><strong>とりあえず試してみる</strong></p>
<p>MyMR には, MapReduce のマナー (?) に従って, WordCount するためのサンプルコードとサンプルデータを同梱してみました.</p>
<p>map/reduce 関数は PHP で書かれています.<br />
<strong><a href="https://github.com/yuya-takeyama/mymr/blob/develop/examples/WordCount.php">WordCount.php</a></strong></p>
<p>MySQL のユーザ名・パスワード等は適宜置き換えて下さい.</p>
<p><script src="https://gist.github.com/1736460.js?file=01-introduction.txt"></script></p>
<p>見事, 入力テーブル内の単語の出現回数を集計することができました.</p>
<p><strong>MyMR の特徴</strong></p>
<ul>
<li>データの入出力はいずれも MySQL のテーブル</li>
<li>入力と出力のデータベースは同じでもいいし別でもいい<br />
(入力はプロダクションサービスの Slave サーバで, 出力はデータ集計用の別サーバ, とかいうこともできる)</li>
<li>map/reduce 関数を PHP で書く</li>
<li>MySQL を意識することは無く, PHP 標準の array にほげほげするだけ</li>
<li>分散/冗長性/耐障害性などについては特に考えていないし, 考える予定も無い<br />
(エラー処理はちゃんとしたい)</li>
<li>並列処理でなく直列処理<br />
(並列処理は出来た方がいいと思っている)</li>
</ul>
<p>まだ「とりあえず動く」程度の状態なので, 色々足りてない状態ではありますが, ギガ/テラバイト級のデータを相手にするのであれば Hadoop とかを使うべきだと思いますし, <strong>MyMR はそのような問題を解決しようとはしていません</strong>.</p>
<p><strong>モチベーション</strong></p>
<ul>
<li>MySQL に直接 MapReduce 処理を行いたい</li>
<li>GROUP BY よりはもっと複雑な処理がやりたい</li>
<li>map/reduce を LL で書きたい</li>
<li>プログラミングモデルとしての MapReduce を活用したい</li>
</ul>
<p>DBMS 上で MapReduce をやりたいのであれば  MongoDB や CouchDB という選択肢がありますし, map/reduce を LL で書きたいというのであれば Hadoop Streaming という選択肢があるでしょう.<br />
そうなると, やはり一番のモチベーションは <strong>MySQL で MapReduce する</strong> ということに尽きるように思います.</p>
<p>MongoDB による MapReduce も JavaScript でカジュアルにできてとても便利です.<br />
ですが, 自分の場合, 普段の仕事だと, そもそものデータはほとんど MySQL に入っているので,</p>
<ol>
<li>mysqldump で csv ファイルを作成</li>
<li>mongoimport で MongoDB にインポート</li>
<li>MongoDB 上で MapReduce</li>
</ol>
<p>みたいな手順を踏む必要があり, 非常に面倒です.<br />
場合によっては mongoexport で csv に出力してさらに MySQL 上にインポート, なんてことをやることもあって, 正直疲れました.</p>
<p><strong>MySQL で</strong> ということの次に重要だと思うのが, <strong>プログラミングモデルとしての MapReduce</strong> です.<br />
これについては書くと長くなりそうなのでやめておきますが, Haskell のような関数型言語をつまみ食いすることで, この辺りの魅力がわかってきたように思います.<br />
(関数型言語における map 関数と Hadoop/MongoDB/MyMR における Map はちょっと違いますが)<br />
伊藤直也さんの <a href="https://github.com/naoya/mapreduce-lite"><strong>MapReduce::Lite</strong></a> なんかも, その辺りにモチベーションがあって作られたのではないか, と想像しています.</p>
<p><strong>何故 PHP か</strong></p>
<p>特に大した理由はありません.<br />
強いていえば仕事で使いたいと思っていて, 周囲で使われているのが PHP である, というだけの話です.</p>
<p>ついでに挙げるなら, PHP では MySQL ドライバが標準で備わっている, というのもあります.<br />
MyMR では PDO を使っており, 普通に構築された LAMP 環境であれば, まず問題無く使えると思います.</p>
<p>とはいえ, 例えば Bundler の使える環境であればそういった依存関係に悩まされることもありませんし, 正直 Ruby で書き直したい.</p>
<p><strong>MyMR の仕組み</strong></p>
<p>仕組みといえるほど複雑なことはやっていませんが…</p>
<p><strong>1: 入力データの取得</strong></p>
<p>これはとても単純で, mymr コマンドの -i (&#8211;input) オプションに渡したテーブルを全件 SELECT するのみです.</p>
<p>今の所全データをガバっとメモリ内に取り込むようになっているので, テーブルサイズに比例してメモリを食います.<br />
非ビッグデータ向けのフレームワークとはいえ, これはさすがにあんまりなので, 何とかするつもりです.</p>
<p>あと, 未実装ですが, WHERE 条件なども指定できれば入力の段階でフィルタできて便利そうなので, やろうと思っています.</p>
<p><strong>2: Map</strong></p>
<p>SELECT で取得した全ての行に対して Map 処理を行います.</p>
<p>MyMR の map 関数では, その中で emit メソッドを実行することで, テンポラリテーブルにデータを INSERT していきます.<br />
関数のプロトタイプは void map(array $record) というシンプルなもので, 1 レコードを表すハッシュ (PHP なので array) を受け取るだけです.</p>
<p>入力テーブルの定義についての制約は特にありません.<br />
通常どんなテーブルでも入力として扱うことができます.</p>
<p>emit にはキーとそれに対応する値を渡すことで, 中間データがテンポラリテーブルに 1 行ずつ挿入されます.<br />
本来は MySQL セッションが終了した時点でテーブルは消えるのですが, 先の WordCount の例でいうと以下のようなテーブルが作成されています.</p>
<p><script src="https://gist.github.com/1736460.js?file=02-tmptable.txt"></script></p>
<p>emit に渡された値は自動的に JSON に変換されています.</p>
<p>JSON 化してるのは構造化データを扱えるようにするためで, この辺りは MongoDB の MapReduce にインスパイアされてます.</p>
<p><strong>3: Shuffle/Sort (?)</strong></p>
<p>Hadoop なんかで言うところの Shuffle/Sort 付近に該当する, と思っているのですが, あんまり自信ないです.<br />
ぶっちゃけると Hadoop 自体を使ったことは無くて, ブログ記事や書籍でつまみ食いした程度の知識しかありません.<br />
(り, りろんはしってる (知らない))</p>
<p>とにかく, ここでは Reduce フェーズの前の下準備として, キーが同一のものをグループ化しています.</p>
<p>MyMR ではカジュアルに GROUP BY と GROUP_CONCAT を使っています.</p>
<p><script src="https://gist.github.com/1736460.js?file=03-shuffle.txt"></script></p>
<p>実際は GROUP_CONCAT の SEPARATOR には改行コードの LF を指定しており, 複数の JSON が改行区切りで連結されたものになります.<br />
要するに複雑なパース無しで複数の JSON を分割できるデリミタであれば何でもよくて, 無難に LF を使っているというだけの話です.</p>
<p>ところで, ここで JSON の代わりに MessagePack を使えれば, それだけである程度高速化できると思うんですが, そのときのデリミタは何にすればいいんでしょう?</p>
<p><strong>4: Reduce</strong></p>
<p>前の Shuffle フェーズで実行したクエリの結果全行に対して, 1 行 1 行 Reduce 処理を行います.</p>
<p>Map と同様, reduce 関数に 1 行 1 行の値を渡していきます.<br />
関数のプロトタイプは array reduce(string $key, array $values) となっています.<br />
$values では GROUP_CONCAT で改行区切りとなっていた JSON を予めパースし, 値の配列として渡されます.</p>
<p>そして返り値のハッシュがそのまま 1 行として -o (&#8211;output) に指定されたテーブルに 1 行 1 行挿入されていきます.</p>
<p>また, map と違って単純な入出力モデルになっているので, テストが書きやすいという利点があります.</p>
<p>そしてこれも map と違って, 挿入するデータは JSON ではなく, ハッシュのキーをカラム名としてレコードにマッピングされます.<br />
そのため, 出力テーブルの定義は reduce 処理に合わせておく必要があります.</p>
<p>これまた map と違って, 出力テーブルでは key という名前のカラムが, キーを格納するために予約されており, reduce 返すキーとしては避ける必要があります.<br />
それ以外は自由ですが, key カラムにはユニークインデックスを設定しておくのが良いでしょう.</p>
<p><strong>まとめ</strong></p>
<p>MyMR について長々と書いてきましたが, この記事で一番主張したいのは「MySQL から直接 MapReduce できたら便利じゃないか」ということに尽きます.<br />
そういう需要があってもよさそうなものですが, ググってみても意外とそれらしい記事は見つからず, じゃあ作ってみようということでできたのが MyMR です.</p>
<p>ほとんどプロトタイプみたいなもので, 作り込みはまだまだこれからですが, 「MySQL で MapReduce する」というアイディアを発表したくて, この記事を書いています.</p>
<p>また, 今回はたまたま MySQL でしたが, 入出力を抽象化して MapReduce をするための何かがあれば, いろいろ捗るんじゃないかなぁという妄想もあります.</p>
<p>ビッグデータは無くとも, ビッグデータ時代に生まれた知見を活かすことはできるんじゃないか, というお話でした.</p>
<p><strong>See also</strong></p>
<ul>
<li><a href="http://d.hatena.ne.jp/naoya/20080511/1210506301">MapReduce &#8211; naoyaのはてなダイアリー</a></li>
<li><a href="http://oss.infoscience.co.jp/hadoop/common/docs/current/mapred_tutorial.html">Map/Reduce チュートリアル</a></li>
<li><a href="http://www.mongodb.org/display/DOCSJP/MapReduce">MapReduce &#8211; Docs-Japanese &#8211; 10gen Confluence</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1706/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>闇 PHP 勉強会で Zend Engine の HashTable について発表した</title>
		<link>http://blog.yuyat.jp/archives/1691</link>
		<comments>http://blog.yuyat.jp/archives/1691#comments</comments>
		<pubDate>Sat, 28 Jan 2012 13:25:19 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[Event]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1691</guid>
		<description><![CDATA[HashTable と HashDos View more presentations from Yuya Takeyama Zend Engine 初心者による, Zend Engine 初心者のための発表という感じで [...]]]></description>
			<content:encoded><![CDATA[<div style="width:425px" id="__ss_11304293"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/taketyan/hash-table-hashdos" title="HashTable と HashDos" target="_blank">HashTable と HashDos</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/11304293" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/taketyan" target="_blank">Yuya Takeyama</a> </div>
</p></div>
<p>Zend Engine 初心者による, Zend Engine 初心者のための発表という感じで話してきました.</p>
<p>今年に入ってから, <strong><a href="http://scribble.yuyat.jp/">scribble</a></strong> というなぐり書き用のブログを始めました.<br />
GitHub Pages 内で <a href="https://github.com/mojombo/jekyll"><strong>Jekyll</strong></a> というツールを使って書いているんですが, Markdown で書いて git commit して git push するだけでサクッと公開できるのでとても気に入っています.</p>
<p>今のところ主に PHP 本体や, そのコアであるところの Zend Engine のコードリーディングが中心で, 今回の発表はこれらの記事をまとめた内容です.</p>
<p>闇 PHP 勉強会でのその他の発表はというと, <a href="http://nimpad.jp/phppeg/">PHP 製のパーサコンビネータ</a>とか, OpenCL とか, <a href="http://d.hatena.ne.jp/do_aki/20110912/1315800142">魔改造 PHP</a> とか様々で, こんな中でハッシュテーブルの実装について話し手も釈迦に説法なんではないかとかいろいろ危惧しましたが, わかりやすかったという声ももらえたようでよかったです.</p>
<p>この発表では, 既に scribble でも紹介している <strong><a href="http://scribble.yuyat.jp/2012/01/21/visualizing-hashdos-with-hashtable-dump.html">hashtable_dump</a></strong> という PHP Extension についても紹介しています.</p>
<p>本当は HashDoS 問題を解決したという Perl や Ruby におけるハッシュテーブルの実装についても調べて発表したかったんですが, 今回は間に合いませんでした.<br />
次回の闇 PHP 勉強会があれば是非それらについて発表できればと思っています.</p>
<p>最後に, 主催の <strong><a href="http://twitter.com/anatoo">@anatoo</a></strong> さん, 会場提供の<a href="http://www.asial.co.jp/">アシアル株式会社</a>さん,  楽しい勉強会をありがとうございました.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1691/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>互換性の無い gem を無理やり bundle install する</title>
		<link>http://blog.yuyat.jp/archives/1628</link>
		<comments>http://blog.yuyat.jp/archives/1628#comments</comments>
		<pubDate>Mon, 02 Jan 2012 12:43:28 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Bundler]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Github]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1628</guid>
		<description><![CDATA[2011-01-03 19:30 追記 rack-config は現在では rack 本体の gem に含まれており, わざわざインストール必要はありませんでした. (GitHub で送っていた Pull request [...]]]></description>
			<content:encoded><![CDATA[<p><strong>2011-01-03 19:30 追記<br />
rack-config は現在では rack 本体の gem に含まれており, わざわざインストール必要はありませんでした.<br />
(GitHub で送っていた Pull request も閉じてます)<br />
ですが, この記事で紹介している Bundler についての説明は特に問題ありません.</strong></p>
<p>お正月休みということでちょっとした Sinatra 製の Web アプリケーションをいじって遊んでいます.</p>
<p>ローカルでは Pow で開発して, Heroku へのデプロイを考えているんですが, 設定をどう管理するか迷いました.<br />
いろいろ調べた結果, .powenv とか使う方法とかあったのですが, .powenv は Heroku 上では使えません.<br />
どうしたものかとさらに探した結果, <a href="https://github.com/jcrosby/rack-config"><strong>rack-config</strong></a> という gem があったのでそれをラップして何とかすることにしました.<br />
(以降はエントリの内容から脱線するので省略. いい感じの方法があれば <a href="http://twitter.com/yuya_takeyama">Twitter</a> とかで教えていただけると幸いです.)</p>
<p>さっそく Gemfile を書いて必要な gem を用意しましょう.<br />
趣味の開発ですし, rack は最新バージョンを指定して, あわよくば地雷を踏み, パッチなど書いて Pull request を送りたい, というのが人情というものでしょう.</p>
<p><script src="https://gist.github.com/1550129.js?file=01-Gemfile.rb"></script></p>
<p>これで bundle install を実行すると, 以下のようにエラーで中断してしまいます.</p>
<div id="attachment_1632" class="wp-caption aligncenter" style="width: 424px"><a href="http://blog.yuyat.jp/archives/1628/bundle-fail" rel="attachment wp-att-1632"><img src="http://blog.yuyat.jp/wp-content/uploads/bundle-fail.png" alt="bundle install に失敗" title="bundle install に失敗" width="414" height="126" class="size-full wp-image-1632" /></a><p class="wp-caption-text">bundle install に失敗</p></div>
<p>これは rack と rack-config の<strong>互換性</strong>による問題です.<br />
rack-config は 2012 年 1 月 2 日現在で丸 3 年程メンテされていない状態で, 依存する rack のバージョンが <strong>~&gt; 0.4</strong> と, かなり古い状態です.<br />
(~&gt; 0.4 というのは 0.4.0 以上 0.5.0 未満という意味です)</p>
<p>今回指定した rack 1.4.0 は, rack-config が依存するバージョンに含まれないため, <strong>依存関係の解決に失敗</strong>し, エラーとなってしまいます.</p>
<p>といっても, これはメタ情報におけるバージョンの指定の問題で, 実際に互換性があるかどうかは別の問題です.<br />
<a href="https://github.com/jcrosby/rack-config/blob/master/lib/rack/config.rb">rack-config の実装は README よりも短くシンプル</a>なもので, 目 rackup した限りでは間違いなく動きそうに見えます.</p>
<p>作者に依頼して依存関係の指定を修正してもらうという手もありますが, 今回は<strong>とりあえずの解決</strong>をするための方法を紹介します.</p>
<p><strong>大まかな手順</strong></p>
<ol>
<li>元のプロジェクトを GitHub 上で fork してローカルに git clone する</li>
<li>ローカルの tmp-repo ブランチ上で *.gemspec の依存関係の指定を修正する</li>
<li>自分のリポジトリに git push する</li>
<li>Gemfile で自分のリポジトリを指定する</li>
</ol>
<p><strong>Bundler</strong> は RubyGems.org からのインストールだけでなく, <strong>Git リポジトリからのインストール</strong>にも対応しています.<br />
それを利用し, オレオレ Rubygems パッケージリポジトリを作って, そこからインストールしよう, というものです.</p>
<p>今回はたまたま元のプロジェクトが GitHub 上にあったので fork するだけで済みましたが, GitHub 上に無い場合も, 手動でリポジトリさえ作れば, あとは同様の手順で実行できます.</p>
<p><strong>1. 元のプロジェクトを GitHub 上で fork してローカルに git clone する</strong></p>
<p>clone については省略しますが, ブランチを切るのがいいでしょう.<br />
一時的なリポジトリということで, tmp-repo という名前にしてみました.</p>
<p><script src="https://gist.github.com/1550129.js?file=02-create-branch.sh"></script></p>
<p><strong>2. ローカルの tmp-repo ブランチ上で *.gemspec の依存関係の指定を修正する</strong></p>
<p><strong>*.gemspec</strong> というのは, <strong>Rubygems パッケージのメタ情報</strong>を定義するファイルです.<br />
依存関係もこのファイルに記述されています.</p>
<p>今回の場合は rack-config.gemspec に以下のような修正を加えました.</p>
<p><script src="https://gist.github.com/1550129.js?file=03-rack-config.gemspec.diff"></script></p>
<p>rack-config は rack 0.4.0 以上 1.5.0 未満に依存する, ということになったので, rack 1.4.0 も含まれるようになりました.</p>
<p><strong>3. 自分のリポジトリに git push する</strong></p>
<p>特に説明は要らないと思いますが念のため.</p>
<p><script src="https://gist.github.com/1550129.js?file=04-git-push.sh"></script></p>
<p><strong>4. Gemfile で自分のリポジトリを指定する</strong></p>
<p>先ほどの Gemfile を以下のように書き換えました.</p>
<p><script src="https://gist.github.com/1550129.js?file=05-Gemfile.rb"></script></p>
<p>fork した自分のリポジトリの URL と, 今回のために作成した tmp-repo ブランチを指定しています.</p>
<p>あとは最初と同じように bundle install を実行するだけです.</p>
<div id="attachment_1653" class="wp-caption aligncenter" style="width: 640px"><a href="http://blog.yuyat.jp/archives/1628/bundle-success" rel="attachment wp-att-1653"><img src="http://blog.yuyat.jp/wp-content/uploads/bundle-success.png" alt="bundle install に成功" title="bundle install に成功" width="630" height="186" class="size-full wp-image-1653" /></a><p class="wp-caption-text">bundle install に成功</p></div>
<p>無理矢理 bundle install することに成功しました!</p>
<p><strong>蛇足: オレはこう思う</strong></p>
<p>今回はオレオレリポジトリを作ってとりあえずの解決を試みる方法を紹介しましたが, せっかくなら作者にも修正を出しておくとよりいいでしょう.<br />
今後その gem を使用するときにいちいちオレオレリポジトリを指定するのは面倒ですし, 他の人にとってもその gem がメンテされた状態で使える方が便利です.</p>
<p>今回の rack-config についても, 実際は以下のような手順を経ています.</p>
<ol>
<li>元のプロジェクトを GitHub 上で fork してローカルに git clone する</li>
<li><strong>ローカルの develop ブランチ上で Bundler を使ってテストできるように修正する</strong></li>
<li><strong>GitHub 上で Pull request を送る</strong></li>
<li><strong>develop ブランチから tmp-repo ブランチを作成する</strong></li>
<li>ローカルの tmp-repo ブランチ上で *.gemspec の依存関係の指定を修正する</li>
<li>自分のリポジトリに git push する</li>
<li>Gemfile で自分のリポジトリを指定する</li>
</ol>
<p>修正を依頼しつつ, それとは別のブランチをオレオレリポジトリにしています.<br />
(この Pull request が取り入れられるのかはまだわかりませんが&#8230;)</p>
<p>ついでに Travis CI で 0.4.0 以上 1.5.0 未満の全ての rack でテストが通ることも確認済みです.</p>
<p>Travis CI 用の設定ファイルは以下のようなスクリプトで, <a href="https://github.com/yuya-takeyama/rack-config/blob/develop/.travis.yml">.travis.yml</a> と <a href="https://github.com/yuya-takeyama/rack-config/tree/develop/gemfiles">gemfiles</a> を生成しました.<br />
Travis CI では複数の gemfiles を指定することで, それぞれで bundle install し, 複数のバージョンの gem に対してテストを行うことができます.</p>
<p><script src="https://gist.github.com/1550129.js?file=06-gen_gemfiles.rb"></script></p>
<p>なお, rack は 0.4.x のあといきなり 0.9.x にバージョンが飛んでいます.</p>
<p>これで, <a href="http://travis-ci.org/#!/yuya-takeyama/rack-config/builds/467701">見事に全てのバージョンでテストが通ることが確認できました.</a><br />
(ここまで必死になることも無いとは思いますが&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1628/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby 用オートローダスクリプト自動生成ツール algerb リリース</title>
		<link>http://blog.yuyat.jp/archives/1616</link>
		<comments>http://blog.yuyat.jp/archives/1616#comments</comments>
		<pubDate>Sat, 31 Dec 2011 14:50:23 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[algerb]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1616</guid>
		<description><![CDATA[最近 PHP ばっかりやってましたが, 年末で時間もあったので久々に Ruby で作ってみました. 2011 年最後の日にして, 初の Rubygems パッケージリリースです. yuya-takeyama/algerb [...]]]></description>
			<content:encoded><![CDATA[<p>最近 PHP ばっかりやってましたが, 年末で時間もあったので久々に Ruby で作ってみました.<br />
2011 年最後の日にして, 初の Rubygems パッケージリリースです.</p>
<ul>
<li><strong><a href="https://github.com/yuya-takeyama/algerb">yuya-takeyama/algerb &#8211; GitHub</a></strong></li>
<li><strong><a href="https://rubygems.org/gems/algerb">algerb | RubyGems.org</a></strong></li>
</ul>
<p><strong>これは何?</strong></p>
<p>まぁタイトルの通りです.</p>
<p>Ruby には <em>Kernel.#autoload</em> というメソッドがあります.<br />
これを利用すればいちいち手動で require しなくても, 対象となるモジュールやクラス名が参照されたタイミングで自動的に require してくれるというものです.</p>
<p>autoload は便利ですが, ライブラリ内のファイル数が増えてくるといちいち手動で書くのは大変になってくるので, じゃあ自動生成すればいいじゃない, ということで作ってみました.</p>
<p><strong>使い方</strong></p>
<p>プロジェクトの Gemfile に適当に設定します.</p>
<p><script src="https://gist.github.com/1544140.js?file=Gemfile"></script></p>
<p>あとは bundler 経由でコマンドを実行するのみです.</p>
<p><script src="https://gist.github.com/1544140.js?file=autoloader-generation"></script></p>
<p>これで ./lib ディレクトリ内を自動的に走査し, ./autoloader.rb というファイルを生成します.</p>
<p><script src="https://gist.github.com/1544140.js?file=autoloader.rb"></script></p>
<p>これぐらいの規模だとそんなにありがたみは無いですが, 例えば Cucumber のような規模のプロジェクトで使用すると, 以下のようなファイルが生成されます.</p>
<p><script src="https://gist.github.com/1544140.js?file=cucumber-autoloader.rb"></script></p>
<p>ただ, これが実際に Cucumber プロジェクト内で正常に使えるかは試しておらず, よくわかりません.<br />
理由は以下に.</p>
<p><strong>仕組み</strong></p>
<p>仕組みはすごく簡単で, ファイルパスからクラス・モジュール名をルールに従って変換し, それをもとに Ruby スクリプト化しているだけです.</p>
<p>例えば, <em>./lib/foo/bar/baz/foo_bar.rb</em> というファイルがあるとすると, 中には <em>Foo::Bar::Baz::FooBar</em> というクラス (またはモジュール) があるに違い無い, という前提で生成しています.<br />
ファイルの中身は一切参照していません.</p>
<p>よって, algerb が正常に動作する条件として, <strong>ファイルとクラス・モジュールの命名がルールに従っている</strong>必要があります.</p>
<p><strong>課題</strong></p>
<p>今のところひとつの ./lib ディレクトリしか対象にできないので, ./vendor ディレクトリ内のライブラリなどは相変わらず require する必要があります.</p>
<p>また, 1 ファイルに複数のクラス・モジュールが存在するなどといった場合にも対応できません.<br />
これを実現するとなると, Ruby パーサなどを用いてもっとちゃんとファイル解析する必要があるでしょう.</p>
<p>あと, 情けない話なんですが, gem コマンド経由でインストールしたときに正常に動作しません&#8230;<br />
gem install した時点で bundle install されてないので, 依存関係を解決することができずに, 起動すらできません.<br />
これはただ単にやり方をしらないだけなので, 調べて直すつもりです.</p>
<p>ちょこちょこ修正するつもりではありますが, 普段 Ruby 開発をやっているわけではないので, どういう仕様にすれば役に立つのかよくわかってなかったりします.<br />
Twitter などでご意見いただけると幸いです.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1616/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Travis CI で PHP 5.4 も CI する, PHPUnit も Behat もやる</title>
		<link>http://blog.yuyat.jp/archives/1540</link>
		<comments>http://blog.yuyat.jp/archives/1540#comments</comments>
		<pubDate>Mon, 19 Dec 2011 19:01:47 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Behat]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[php-build]]></category>
		<category><![CDATA[phpenv]]></category>
		<category><![CDATA[PHPUnit]]></category>
		<category><![CDATA[Travis CI]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1540</guid>
		<description><![CDATA[この記事は PHP5.4 Advent Calendar jp: 2011 の 20 日目です. 前日: 次のプロジェクトで PHP 5.4 の採用を提案するための 3 つのポイント (@co3k さん) 翌日: (@k [...]]]></description>
			<content:encoded><![CDATA[<p>この記事は <a href="http://atnd.org/events/22473">PHP5.4 Advent Calendar jp: 2011</a> の 20 日目です.</p>
<ul>
<li>前日: <strong><a href="http://co3k.org/blog/23">次のプロジェクトで PHP 5.4 の採用を提案するための 3 つのポイント</a></strong> (<a href="http://twitter.com/co3k">@co3k さん</a>)</li>
<li>翌日: (<a href="http://twitter.com/kokkekun">@kokkekun さん</a>)</li>
</ul>
<p><strong>Travis CI とは</strong></p>
<p><strong><a href="http://travis-ci.org">Travis CI</a></strong> は, <strong>Continuous Integration</strong> (CI: 継続的インテグレーション) を実行するクラウド環境です.<br />
GitHub に push すると, Travis CI の VM 上に通知が行われ, GitHub リポジトリからのチェックアウトや, ユニットテストの実行が行われます.<br />
ユニットテストの実行は成功/失敗の結果により通知が行われ, また, 履歴も Travis CI 上に残ります.</p>
<p>元々は Ruby 専用のサービスだったと思いますが, その後 Clojure や Node.js などをサポートし, 1 ヶ月ぐらい前に PHP までもサポートされました.</p>
<p><strong>Travis CI を利用する PHP プロジェクト</strong></p>
<ul>
<li><a href="http://travis-ci.org/#!/symfony/symfony"><strong>Symfony2</strong></a></li>
<li><a href="http://travis-ci.org/#!/doctrine/doctrine2"><strong>Doctrine2</strong></a></li>
<li><a href="http://travis-ci.org/#!/Behat/Behat"><strong>Behat</strong></a></li>
<li><a href="http://travis-ci.org/#!/squizlabs/PHP_CodeSniffer"><strong>PHP_CodeSniffer</strong></a></li>
</ul>
<p>これら以外にも Symfony 関連のライブラリやバンドルは多く登録されています.</p>
<p>ところで, 国産のものだと今のところは <a href="http://travis-ci.org/#!/diggin/Diggin_Http_Charset"><strong>Diggin_Http_Charset</strong></a> ぐらいしか把握していません.<br />
日本語の情報はまだほとんど無いに等しい状況なので, 日本国内の, 少なくとも PHP コミュニティにおいてはまだあまり認知されていないように思えます.</p>
<p>記事にするにはまだまだ調べが足りないのですが, とりあえず日本の PHP コミュニティにも広まって欲しいと思い, 紹介してみることにしました.</p>
<p><strong>Travis CI で CI するまでの手順</strong></p>
<p>何はともあれ, 実際に GitHub のリポジトリを登録してみましょう.</p>
<p>大まかに以下のような流れとなります.</p>
<ol>
<li>GitHub でのアカウント登録</li>
<li>PHP プロジェクトのリポジトリを用意</li>
<li>リポジトリ内に専用の設定ファイル .travis.yml を用意</li>
<li>GitHub アカウントでの OAuth により Travis CI にサインイン</li>
<li>Travis CI のアカウント情報を GitHub のリポジトリの Service Hooks に登録</li>
<li>GitHub リポジトリに git push</li>
</ol>
<p>まずは, <a href="http://travis-ci.org">Travis CI</a> にサインインします.<br />
GitHub のアカウントさえあれば, OAuth で簡単にサインインできます.</p>
<p>PHP のプロジェクトは何でもいいですが, とりあえずは PHPUnit のテストが書かれているものが必要です.<br />
ちょっと試したいけど手頃なリポジトリが無い, という場合は, 以下のリポジトリを fork してやってみるのもいいでしょう.</p>
<ul>
<li><strong><a href="https://github.com/lsmith77/travis-ci-php-example">lsmith77/travis-ci-php-example &#8211; GitHub</a></strong></li>
</ul>
<p>Travis CI 用の設定ファイル .travis.yml ファイルは, とりあえず以下のようなものを用意しましょう.<br />
これを, リポジトリ上のルートディレクトリに配置します.</p>
<p><script src="https://gist.github.com/1498081.js?file=1.travis.yml"></script></p>
<p>設定項目は他にもたくさんあるので, 詳細は公式ドキュメントの <a href="http://about.travis-ci.org/docs/user/languages/php/">Building a PHP Project</a> を参照してください.</p>
<p>これで, git push 時に PHP5.3 と PHP5.4 の環境でテストが実行されます.<br />
(そういえばこの記事は PHP5.4 Advent Calendar でした)</p>
<p>テストの実行には明示していませんが, デフォルトでは phpunit コマンドが実行されます.<br />
PHPUnit ではデフォルトで phpunit.xml を設定ファイルとして読み込むので, これもリポジトリルートに置いておきましょう.<br />
(ところで, よく phpunit.xml.dist という名前にしているものがありますけど, あれってどういう意味なんでしょう&#8230;)</p>
<p>リポジトリの Service Hooks の指定, つまりこれは push 等のイベントの発生時に Travis CI に通知を行う機能ですが, これは Travis CI 上の画面から簡単にできます.<br />
フリックスイッチを ON にするだけです.</p>
<div id="attachment_1556" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.yuyat.jp/archives/1540/beebf40cbfa95f6c817561fe296a8b85" rel="attachment wp-att-1556"><img src="http://blog.yuyat.jp/wp-content/uploads/beebf40cbfa95f6c817561fe296a8b85-300x185.png" alt="リポジトリの選択" title="リポジトリの選択" width="300" height="185" class="size-medium wp-image-1556" /></a><p class="wp-caption-text">リポジトリの選択</p></div>
<p>ですが, このリポジトリ一覧は最大で 30 しか表示されない問題があるようで, 登録したいリポジトリが表示されない場合は, 手動で登録する必要があります.<br />
手動での登録は GitHub のリポジトリから Admin -&gt; Service Hooks -&gt; Travis と進み, 必要な情報を入力します.</p>
<p>Domain と User は通常空のままでいいので, <strong>Token</strong> のみ Travis CI の画面上からコピーし, <strong>Active</strong> にチェックを入れた上で, <strong>Update Settings</strong> します.</p>
<p>これで Travis CI で CI を行う準備が整いました.<br />
あとは, git push すればそのタイミングでビルドが実行されるので, Travis CI の画面上で確認しましょう.<br />
また, GitHub の Service Hooks の画面で <strong>Test Hook</strong> ボタンを押すことでもビルドが始まります.<br />
なお, このときは GitHub 上でデフォルトで表示される設定に鳴っているブランチ (デフォルトは master) に対してビルドが行われるようです.</p>
<p>Travis CI のワーカの稼働状況によってはなかなか結果が反映されないこともあるので, ご注意ください.</p>
<p>以下は, 細かい設定について説明します.</p>
<p><strong>vendor ディレクトリへの対応</strong></p>
<p>開発しているプロジェクトが依存する外部ライブラリは, よく vendor というディレクトリに入れられています.<br />
vendor ごとリポジトリに放り込むこともできますが, 通常は vendor は .gitignore に登録して, リポジトリには登録しないことが多いでしょう.</p>
<p>その場合, vendor ディレクトリに対象のライブラリを自動でインストールできる必要があります.</p>
<p>今回は, 最近開発中の <strong><a href="https://github.com/yuya-takeyama/Speciphy">Speciphy</a></strong> という BDD フレームワークを例に説明を行います.</p>
<p>今回は, Speciphy は PHPSpec に依存しているので, 事前に PHPSpec をインストールしておかないと, Travis CI 上でテストを実行することができません.<br />
そこで, 以下のようなインストールスクリプトを, install-vendor.sh として用意します.</p>
<p><script src="https://gist.github.com/1498081.js?file=install-vendor.sh"></script></p>
<p>今回は, PHPSpec を pyrus.phar でインストールしています.<br />
(pyrus.phar というのは次世代の pear コマンドです)<br />
予め必要となる pear channel を登録しておくことで, 対話無しで全自動でインストールが完了します.</p>
<p>なお, Symfony2 だと git submodule を利用して vendor を管理していると聞きますが, これについてはあまり知らないので割愛します.<br />
やり方はいろいろあると思うので, フレームワークに合わせたり, 自分の好きな方法を探してみてもいいでしょう.<br />
(<a href="http://packagist.org/about-composer">Composer</a> を使うのも面白いですね)</p>
<p>そして, .travis.yml に, 先ほどのインストールスクリプトを, ビルドの前の準備として実行するよう, 追記しましょう.</p>
<p><script src="https://gist.github.com/1498081.js?file=2.travis.yml"></script></p>
<p>pyrus による vendor 対応については以下の記事を参考にしました.</p>
<ul>
<li><strong><a href="http://saltybeagle.com/2011/01/using-pyrus-to-manage-pear-installable-vendor-libs/">Using Pyrus To Manage PEAR Installable Vendor Libs</a></strong></li>
</ul>
<p><strong>Behat によるテストも行う</strong></p>
<p>デフォルトでは PHPUnit によるテストが実行されるのみですが, Behat によるテストも実行できるようにします.</p>
<p>テストとして実行されるコマンドは, .travis.yml で script という項目にコマンドを指定することで可能です.</p>
<p>ところで, ビルドの成功/失敗の判定は, コマンドの終了ステータスで行われているようです.<br />
終了ステータスが 0 なら成功, それ以外なら失敗, という具合です.</p>
<p>つまり, 終了ステータスをきちんと指定しているテスティングフレームワークであれば, 基本的に何でも使えることになります.</p>
<p>そこで, テストを実行するためのスクリプトとして, 以下のような run-test.php を用意します.</p>
<p><script src="https://gist.github.com/1498081.js?file=run-test.sh"></script></p>
<p>環境変数 TESTING_FRAMEWORK が PHPUnit なら PHPUnit を実行し, Behat なら Behat を phar ファイルでダウンロードして実行する, というものです.<br />
スクリプトの最後に終了ステータスを指定して exit しているので, テストの実行が成功/失敗のいずれでも適切に通知されます.</p>
<p>そして .travis.yml にも再度追記を行います.</p>
<p><script src="https://gist.github.com/1498081.js?file=3.travis.yml"></script></p>
<p>今度は env という項目を追加しています.<br />
これは, env を配列で複数指定することによって, その数だけテストを実行するというものです.</p>
<p>今回は PHP のバージョンに 5.3 と 5.4 の 2 種類, テスティングフレームワークに PHPUnit と Behat の 2 種類指定しているので, 2 x 2 で合計 4 パターンのビルドが行われます.<br />
うまくいけば, 以下のような結果が得られます.<br />
(設定は上記のものと多少異なります)</p>
<div id="attachment_1581" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.yuyat.jp/archives/1540/5d2e2571e116aa974a911fb6b70b44f7" rel="attachment wp-att-1581"><img src="http://blog.yuyat.jp/wp-content/uploads/5d2e2571e116aa974a911fb6b70b44f7-300x188.png" alt="Travis CI 実行結果" title="Travis CI 実行結果" width="300" height="188" class="size-medium wp-image-1581" /></a><p class="wp-caption-text">Travis CI 実行結果</p></div>
<p><strong>PHP の Travis CI を支える技術</strong></p>
<p>Travis CI では, テストを実行する際の環境の実行に <a href="https://github.com/CHH/phpenv"><strong>phpenv</strong></a> が使われています.<br />
また, PHP のビルドには当初 <strong><a href="http://sourceforge.net/p/phpfarm/wiki/Home/">phpfarm</a></strong> が, そして今後は <strong><a href="https://github.com/CHH/php-build">php-build</a></strong> に切り替わるようです.</p>
<p>どのように使われているかは, <a href="https://github.com/travis-ci/travis-cookbooks/tree/master/vagrant_base">このあたり</a>を見れば何となくわかると思います.<br />
(ただし, master がデプロイされているとは限らないので, これが最新の状態とは限らないので注意は必要ですが)</p>
<p>phpenv と php-build については以前に以下のような記事を書いていますので, これらが参考になれば幸いです.</p>
<ul>
<li><strong><a href="http://blog.yuyat.jp/archives/1461"> 第57回PHP勉強会＠東京で開発環境構築について話して来た </a></strong></li>
<li><strong><a href="http://blog.yuyat.jp/archives/1446">phpenv で複数の PHP 環境を管理する</a></strong></li>
<li><strong><a href="http://blog.yuyat.jp/archives/1376">php-build で PHP 5.4.0 beta1 をビルドする</a></strong></li>
</ul>
<p><strong>蛇足: オレはこう思う</strong></p>
<p>Travis CI がどういう組織で作られているのかはまだよくわかってないのですが, <a href="https://github.com/travis-ci">GitHub のアカウントページ</a>を見る限りはそれぞれ所属はバラバラですし, IT ベンチャーとかではなく, コミュニティベースの活動による成果, ということなのでしょうか.</p>
<p>Travis CI の PHP 対応にあたっては, <strong>phpenv</strong> と <strong>php-build</strong> の作者である <a href="https://github.com/CHH"><strong>CHH</strong></a> さん, それらを Travis CI に取り入れるべく多くのパッチを提供した <a href="https://github.com/loicfrering"><strong>loicfrering</strong></a> さんを初め, 何人もの開発者が関わっているようです.</p>
<p>こんな風にありもののツールと, 多方面からの強力が実を結び, 今までには無い手軽さで CI 環境が手に入れられるようになったことは大変素晴らしいことだと思います.</p>
<p>Travis CI 自体もオープンソース活動をさらに加速させるものだと思いますし, これからの PHP コミュニティにも希望が持てると感じます.</p>
<p>フレームワークやライブラリを開発している皆さんは, 導入を検討してみてはいかがでしょうか.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1540/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>例えば, Singleton を避ける</title>
		<link>http://blog.yuyat.jp/archives/1500</link>
		<comments>http://blog.yuyat.jp/archives/1500#comments</comments>
		<pubDate>Tue, 13 Dec 2011 15:25:53 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Test Driven Development]]></category>
		<category><![CDATA[未分類]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Singleton]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1500</guid>
		<description><![CDATA[この記事は TDD Advent Calendar jp: 2011 の 14 日目です. 前日: TDD戦略 -TDDを導入し進化させる方法- #TDDAdventJP (@kyon_mm さん) 翌日: TDDに対し [...]]]></description>
			<content:encoded><![CDATA[<p>この記事は <a href="http://atnd.org/events/22027">TDD Advent Calendar jp: 2011</a> の 14 日目です.</p>
<ul>
<li>前日: <strong><a href="http://d.hatena.ne.jp/kyon_mm/20111213/1323711282">TDD戦略 -TDDを導入し進化させる方法- #TDDAdventJP</a></strong> (<a href="http://twitter.com/kyon_mm">@kyon_mm さん</a>)</li>
<li>翌日: <strong><a href="http://blog.livedoor.jp/gab_km/archives/1413205.html">TDDに対して思っていること</a></strong> (<a href="http://twitter.com/gab_km">@gab_km さん</a>)</li>
</ul>
<p><strong>この記事の概要</strong></p>
<ul>
<li>TDD で開発することで設計上の問題点に気づきやすくなる</li>
<li>Singleton はグローバル変数である</li>
<li>Singleton の使用はできる限り避けるべきである</li>
</ul>
<p><strong>テスタビリティを意識しよう</strong></p>
<p>TDD では, 原則としてユニットテストを書いてから実際のコードを実装します.<br />
なので, 自然と「<strong>テストのしやすさ</strong> (<strong>テスタビリティ</strong>)」を意識して実装することになります.</p>
<p>そして, TDD においては一般的に, テスタビリティを意識することで, <strong>設計が改善</strong>されるとされています.</p>
<p>オブジェクト指向には難しい概念がたくさん登場します.<br />
単一責任の原則 (Single Responsibility Principle) とか, 関心事の分離 (Separation of Concerns)とか, 依存性の注入 (Dependency Injection) とか…<br />
これらを, 書籍などで読むだけで理解できた, という人は少ないのではないでしょうか.<br />
少なくとも私は, TDD を実践することで初めて, これらの原則の言いたいことを実感し, 理解につなげることができたと考えています.</p>
<p><strong>オブジェクト指向設計の大切なことは TDD に学んだ</strong>, と言っても過言ではありません.<br />
あまりにもたくさんのことを学んだので, それらをここで全て紹介するのは無理なことです.<br />
なので, 今回はその中から一つだけ, 簡単なものを紹介しようと思います.</p>
<p>この記事では, 明日から意識できるポイントとして, <strong>例えば, Singleton を避ける</strong>, ということについて紹介します.</p>
<p><strong>Singleton とは</strong></p>
<p>いわゆる <a href="http://www.amazon.co.jp/dp/0201633612/yuyat-22">Gang of Four の書籍</a>で紹介されているデザインパターンのひとつで, 以下のようなことを実現するために利用されます.</p>
<ul>
<li>あるクラスのインスタンスが 1 つであることを保証する</li>
<li>常に同一へのインスタンスを取得するためのアクセスポイントを提供する</li>
</ul>
<p>数あるデザインパターンの中でも比較的理解しやすく, 実装も簡単であるため, これを最初に覚えたという方も多いでしょう.<br />
私自身もそうであったように思います.</p>
<p><strong>Singleton パターンを適用してみる</strong></p>
<p>例えば, PHP においては以下のように実装されます.<br />
ここでは, ありがちな例として, アプリケーション中からグローバルに参照される Config (設定) クラスを作ってみましょう.</p>
<p><script src="https://gist.github.com/1462169.js?file=01-Config.php"></script></p>
<p>要点は以下の 3 点です.</p>
<ul>
<li>コンストラクタ (__construct メソッド) を private にすることで, new を禁止している</li>
<li>代わりに getInstance() という static メソッドでオブジェクトの生成をする</li>
<li>getInstance() では初回だけ Config オブジェクトを生成して返すが, 次回以降は最初に作ったオブジェクトをそのまま返す</li>
</ul>
<p><strong>Singleton をテストする</strong></p>
<p>次に Config オブジェクトをテストするコードを書いてみましょう.<br />
テスティングフレームワークには PHPUnit を使用します.</p>
<p><script src="https://gist.github.com/1462169.js?file=02-ConfigTest.php"></script></p>
<p>このふたつのテストはいずれも成功します.</p>
<div id="attachment_1525" class="wp-caption aligncenter" style="width: 176px"><a href="http://blog.yuyat.jp/archives/1500/attachment/1" rel="attachment wp-att-1525"><img src="http://blog.yuyat.jp/wp-content/uploads/1.png" alt="Green" title="Green" width="166" height="73" class="size-full wp-image-1525" /></a><p class="wp-caption-text">テストは問題無く通った</p></div>
<p>ですが, 記述する順序を逆にしてみると, いとも簡単に失敗してしまいます.</p>
<div id="attachment_1526" class="wp-caption aligncenter" style="width: 469px"><a href="http://blog.yuyat.jp/archives/1500/attachment/2" rel="attachment wp-att-1526"><img src="http://blog.yuyat.jp/wp-content/uploads/2.png" alt="Red" title="Red" width="459" height="165" class="size-full wp-image-1526" /></a><p class="wp-caption-text">テストは壊れてしまった</p></div>
<p>一体, どうしてでしょうか.</p>
<p><strong>Singleton はグローバル変数である</strong></p>
<p>クラスを定義して, クラスメソッドを通してのアクセスを行っていますが, Config クラスのオブジェクトはグローバルに参照可能です.<br />
本来ローカルスコープであるはずのメソッド間を超えて, 状態が共有されてしまいます.<br />
そのため, 一度設定値 foo がセットされると, その後のテストで「foo がセットされていない状態」をテストすることができなくなってしまいました.</p>
<p>このように, Singleton パターンを適用したクラスのオブジェクトは, <strong>本質的にはほとんどグローバル変数</strong>なのです.</p>
<p><strong>テストは新鮮なうちに</strong></p>
<p>ユニットテストを書く上で大切なことは, 出来る限り<strong>クリーンな状態</strong>で始めることです.</p>
<p>グローバル変数, データベース, ファイルシステムなどは, <strong>状態</strong>として考えることができます.<br />
コードやテストがこれらの状態に依存してしまうと, 状態の変化に弱くなり, <strong>壊れやすく</strong>なります.</p>
<p>Singleton でない通常のクラスであれば, 複数のテストメソッド間で状態を共有されません.<br />
スコープがテストメソッドごとに区切られるので, テスト対象のオブジェクトはガベージコレクションにより, 二度と再利用されないためです.<br />
(もちろん, テストケースクラスのインスタンス変数などに入れてしまえば別ですが)</p>
<p>Singleton では, このガベージコレクションによる状態のクリアが起こらないため, <strong>前のテストコンテキストを引きずったまま</strong>, 次のテストを実行することになってしまいます.<br />
複数のテストが影響し合うことによりメンテナンス性が下がるだけでなく, <strong>暗黙的なコンテキストの増大</strong>により, 理解もしづらくなります.</p>
<p><strong>さらなる問題</strong></p>
<p>Config 自体はとてもシンプルなので, さほど問題にはならないかもしれません.<br />
ですが, Config::getInstance() がアプリケーションのあちこちで呼び出されていたらどうでしょうか.</p>
<p>例えば, ウェブアプリケーションにおいて, アプリケーションそれ自体を表す Application クラスについて考えてみます.</p>
<p>Application は設定によりデバッグモードの On/Off が切り替えられるとしましょう.<br />
その設定は, Config オブジェクトが保持することになります.</p>
<p>デバッグモードであるかどうかは, Application オブジェクトの isDebug() メソッドで確認できます.<br />
今度はそれをテストするコードを書いてみましょう.</p>
<p><script src="https://gist.github.com/1462169.js?file=03-ApplicationTest.php"></script></p>
<p>そしてこのテストが通るように Application クラスを実装します.</p>
<p><script src="https://gist.github.com/1462169.js?file=04-Application.php"></script></p>
<p>これで, テストは問題なく通ります.<br />
以下は Config のテストもあわせて実行した結果です.</p>
<div id="attachment_1527" class="wp-caption aligncenter" style="width: 171px"><a href="http://blog.yuyat.jp/archives/1500/attachment/3" rel="attachment wp-att-1527"><img src="http://blog.yuyat.jp/wp-content/uploads/3.png" alt="Green" title="Green" width="161" height="64" class="size-full wp-image-1527" /></a><p class="wp-caption-text">テストは問題無く通った</p></div>
<p>ですが, さっきと同じで, このテストも順序を逆にすると失敗してしまいます.</p>
<div id="attachment_1528" class="wp-caption aligncenter" style="width: 507px"><a href="http://blog.yuyat.jp/archives/1500/attachment/4" rel="attachment wp-att-1528"><img src="http://blog.yuyat.jp/wp-content/uploads/4.png" alt="Red" title="Red" width="497" height="171" class="size-full wp-image-1528" /></a><p class="wp-caption-text">テストはまたしても壊れてしまった</p></div>
<p>原因は, 先ほど Config のテストが失敗したのと全く同じです.<br />
既に debug という設定値が入ってしまっているため, false を明示的に値をセットしない限りは, デバッグする設定のままになります.</p>
<p>このように, Singleton で実装したクラスそれ自体だけでなく, それを呼び出すクラスにまで, <strong>テストのしにくさが伝染してしまう可能性</strong>があるのです.</p>
<p><strong>処方箋 1: 状態を初期化できるようにする</strong></p>
<p>Config クラスのテストしにくさは, 状態がクリーンでないことにありました.<br />
そこで, init() メソッドを実装することで, 状態を初期化できるようにしてみます.</p>
<p><script src="https://gist.github.com/1462169.js?file=05-Concig.php"></script></p>
<p>テストもこのように書き換えます.</p>
<p><script src="https://gist.github.com/1462169.js?file=06-ConfigTest.php"></script></p>
<p>変更点は, Config::getInstance() した後に, init() を呼び出すようにしている点のみです.</p>
<p>これにより, いずれのテストも<strong>クリーンな状態</strong>でテストが実行されることになったので, 例え順番を変えても失敗しなくなりました.<br />
Application クラスにおいても, 同じアプローチを採ることで, テストの実行順序に依存することは無くなります.</p>
<p><strong>処方箋 2: 依存性の注入 (Dependency Injection) の利用</strong></p>
<p>とはいえ, これで問題が無くなったわけではありません.<br />
この Application クラスには, Config というクラス名が<strong>ハードコード</strong>されており, 2 つのクラスは<strong>密結合</strong>になってしまっています.</p>
<p>これでは, Config に似た動きをした別のクラス (例えば CachedConfig とか) を作っても, 差し替えるには全ての Config を書き換える必要が出てしまいます.</p>
<p>ではどうするか.<br />
オブジェクト指向が本来持つ<strong>モジュール性</strong>を活かすのであれば, <strong>引数</strong>で Config オブジェクトを渡すことを検討しましょう.<br />
ここでいう引数とは, コンストラクタ引数でも, メソッド引数のどちらでも構いません.</p>
<p><script src="https://gist.github.com/1462169.js?file=07-Application.php"></script></p>
<p>先ほどよりもややコードが増えてしまいましたが, Config クラスのハードコードが無くなりました.<br />
Application と Config の間の結合は緩くなり, CachedConfig や YamlConfig など, 同じように振る舞う<strong>別クラスへの差し替えが容易になりました</strong>.<br />
また, <strong>モック</strong>や<strong>スタブ</strong>を使ってのユニットテストも書きやすくなっています.</p>
<p>このように, 依存するオブジェクトのクラス名をハードコードするのではなく, 引数で渡すことを<strong>依存性の注入</strong> (<strong>Dependency Injection</strong>) といいます.</p>
<p>ところで, クラス名のハードコードが問題になるのは, 何も Singleton だけの問題ではありません.<br />
例え Singleton ではなくとも, new するクラス名をハードコードすれば, 同じようなことが問題になります.</p>
<p>とはいえ, Singleton を利用すると, getInstance() メソッドを利用した依存にしてしまいがちです.<br />
出来る限り依存性の注入を利用し, <strong>クラス名をハードコードする箇所を最小限に留める</strong>ことで, 後の改修時のコストを大幅に下げることができます.</p>
<p><strong>処方箋 3: そのクラスは本当に Singleton なのか</strong></p>
<p>あなたが今実装しようとしているクラスは, 本当に唯一なのでしょうか.<br />
また, 通常唯一であるとしても, コンストラクタを private にしないと実現できないことなのでしょうか.</p>
<p>確かに, Singleton の「常に同一のインスタンスを返す」という特性は便利です.<br />
ですが, 少なくとも私の経験においては, 「インスタンスが 1 つであることの保証」は, そんなに気張るほどのことでは無かったのではないか, と考えてしまいます.</p>
<p>また, 見方を変えれば, Singleton は, そのクラス本来の役割 (Config であれば設定の保持) とは別にもうひとつ, 「オブジェクト生成の管理」という, <strong>全く違った責任</strong>を持ってしまっています.<br />
これは, <strong>単一責任の原則に違反</strong>していると言えるでしょう.</p>
<p>これをどう解決するか.<br />
少々場当たり的ですが, 例えば Config と, その生成を責任とする ConfigManager に分割する, といったことが考えられます.</p>
<p><script src="https://gist.github.com/1462169.js?file=08-ConfigManager.php"></script></p>
<p>この実装自体はあまりオススメしませんが, とりあえず設定の保持 (Config) という責任と, 設定オブジェクト生成の管理 (ConfigManager) という責任を, 個別のクラスに<strong>分割</strong>することができました.<br />
これにより, Config クラスのコンストラクタを private にするという縛りは無くとも, ConfigManager を利用する限りにおいては, 常に同一のインスタンスを得ることができるようになりました.</p>
<p>コンストラクタが使用できる以上は, オブジェクトの生成は自由になったので, テスト時は毎回オブジェクトを生成・破棄し, クリーンな状態でのテストが可能になりました.<br />
もう init() は必要ありません.</p>
<p><script src="https://gist.github.com/1462169.js?file=09-ConfigTest.php"></script></p>
<p>テストメソッドごとにコンテキストが分割されたので, ガベージコレクション任せで安心してテストに集中することができるようになりました.</p>
<p><strong>まとめ</strong></p>
<p>Singleton の話ばかりしましたが, この記事で私が言いたいのは, <strong>TDD で開発することで設計上の問題点に気づきやすくなる</strong>, ということです.</p>
<p>TDD の実践から学べることは多いにあるので, まだやったことないという方には, まず趣味の開発でいいので, 軽い気持ちでやってみることをオススメします.<br />
業務に TDD 自体を導入する前の段階でも, 設計について新たな目線を得ることができるので, 何かしら良い効果を得ることでしょう.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1500/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第57回PHP勉強会＠東京で開発環境構築について話して来た</title>
		<link>http://blog.yuyat.jp/archives/1461</link>
		<comments>http://blog.yuyat.jp/archives/1461#comments</comments>
		<pubDate>Sat, 12 Nov 2011 15:17:27 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[Event]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php-build]]></category>
		<category><![CDATA[phpenv]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1461</guid>
		<description><![CDATA[最近イチオシの php-build と phpenv について紹介してきました. Building Development Environment with php-build and phpenv View more  [...]]]></description>
			<content:encoded><![CDATA[<p>最近イチオシの <strong><a href="https://github.com/CHH/php-build">php-build</a></strong> と <strong><a href="https://github.com/CHH/phpenv">phpenv</a></strong> について紹介してきました.</p>
<div style="width:425px" id="__ss_10126898"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/taketyan/building-development-environment-with-phpbuild-and-phpenv" title="Building Development Environment with php-build and phpenv" target="_blank">Building Development Environment with php-build and phpenv</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10126898" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/taketyan" target="_blank">Yuya Takeyama</a> </div>
</p></div>
<p>内容はほぼ最近のブログ記事をまとめた感じです.</p>
<ul>
<li><strong><a href="http://blog.yuyat.jp/archives/1376">php-build で PHP 5.4.0 beta1 をビルドする</a></strong></li>
<li><strong><a href="http://blog.yuyat.jp/archives/1446">phpenv で複数の PHP 環境を管理する</a></strong></li>
</ul>
<p>一度ブログに書いたものを敢えて発表ネタにしたのにはいくつか理由があります.<br />
(もちろん, 一度記事にまとめたネタなのでスライドに起こしやすい, というのもありますが&#8230;)</p>
<ul>
<li>もっと色んな人に知って欲しい</li>
<li>もっといろんな人に使って欲しい</li>
<li>まだまだこなれていない部分があり, フィードバックが必要</li>
<li>フィードバックやパッチによりもっと改善されるはず</li>
</ul>
<p>というわけで皆さんどんどん使いましょう.</p>
<p><strong>類似のツールについて</strong></p>
<p><strong>php-build</strong> および <strong>phpenv</strong> と類似の機能をもったツールは他にもあります.<br />
勉強会でも, 例えば <strong><a href="http://d.hatena.ne.jp/hnw/20090110">phpall</a></strong> とはどう違うのか, という質問がありました.</p>
<p>結論から言うと, 私は他のツールは特に使ったことが無いのでよくわかりません.<br />
ですが, もともと <strong>rbenv</strong> は Ruby コミュニティではかなり人気のツールですし, 便利な機能はいろいろと揃っており, 比較的失敗の無い選択肢だと考えています.</p>
<p>また, <strong>phpall</strong> の違いとして, <strong>phpall</strong> は各バージョンのバイナリをそれぞれ php-5.2.8 といった, バージョン番号付きのファイル名にしているようですが, <strong>phpenv</strong> は php コマンド自体を自由に切り替えます.<br />
特定のコードを複数のバージョンで一気に実行する, というときには <strong>phpall</strong> が便利そうですが, ライブラリの開発等には <strong>phpenv</strong> の方が適していると思われます.<br />
また, <strong>phpenv</strong> においては pyrus, phar, phpunit といったコマンドも各バージョンごとに試すことができる, というのも大きな利点です.</p>
<p><strong>phpenv のプラグイン機能について</strong></p>
<p>元々, これまでのブログ記事をまとめただけの発表にするつもりでしたが, ひとつだけおもしろい機能を見つけたので, そこだけ新ネタです.<br />
<strong>phpenv</strong> の元になっている <strong><a href="https://github.com/sstephenson/rbenv">rbenv</a></strong> にはプラグインという機能があり, 専用のディレクトリにシェルスクリプトを配置するだけで簡単にサブコマンドを登録できる, というものです.<br />
当然 <strong>phpenv</strong> でも使える機能です.</p>
<p><strong>phpenv each によるコマンドの一斉実行</strong></p>
<p><strong>rbenv</strong> のプラグインとして公開されているものの中で, とりあえず <strong><a href="https://github.com/chriseppstein/rbenv-each">rbenv-each</a></strong> というものをつかってみました.<br />
これは <strong>rbnev</strong> (もしくは <strong>phpenv</strong>) の管理下にある全てのバージョンのバイナリで, 指定したコマンドを実行する, というものです.</p>
<p>とりあえず, php -v によるバージョンの確認を試してみました.</p>
<div id="attachment_1472" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.yuyat.jp/archives/1461/9a04e69cdf25063d6644ead4a8636647" rel="attachment wp-att-1472"><img src="http://blog.yuyat.jp/wp-content/uploads/9a04e69cdf25063d6644ead4a8636647-300x239.png" alt="phpenv each によるバージョンの一斉確認" title="phpenv each によるバージョンの一斉確認" width="300" height="239" class="size-medium wp-image-1472" /></a><p class="wp-caption-text">phpenv each によるバージョンの一斉確認</p></div>
<p>これ自体はあまり意味の無い例ですが, 例えば <strong>PHPUnit</strong> によるユニットテストを, 複数のバージョンの PHP で一斉に実行できるすれば, ライブラリ作者に取ってはかなり便利なのではないでしょうか.<br />
それについてはいずれ調べて, また記事にしたいと思います.</p>
<p>このように, <strong>php-build</strong> と <strong>phpenv</strong> にはまだまだ便利な使い方がたくさんあるはずです.<br />
利用者が増えることで, そういったノウハウが発掘され, 共有されることを心から願います.</p>
<p>最後になりますが, 今回の勉強会の主催の <a href="http://twitter.com/gusagi"><strong>@gusagi</strong></a> さん, そして会場提供の<strong><a href="http://voyagegroup.com/">株式会社 VOYAGE GROUP</a></strong> さん, 楽しい勉強会を本当にありがとうございました.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1461/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>phpenv で複数の PHP 環境を管理する</title>
		<link>http://blog.yuyat.jp/archives/1446</link>
		<comments>http://blog.yuyat.jp/archives/1446#comments</comments>
		<pubDate>Sun, 23 Oct 2011 08:01:21 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[php-build]]></category>
		<category><![CDATA[phpenv]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1446</guid>
		<description><![CDATA[複数のバージョンの PHP をコマンドだけに簡単に切り替えるための phpenv というツールと, そのインストール方法や, php-build とのについて説明しています.]]></description>
			<content:encoded><![CDATA[<p><strong>phpenv とは</strong></p>
<p><a href="http://blog.yuyat.jp/archives/1446/e5f956424a167079457ff4c458a09e12" rel="attachment wp-att-1457"><img src="http://blog.yuyat.jp/wp-content/uploads/e5f956424a167079457ff4c458a09e12.png" alt="phpenv" title="phpenv" width="665" height="273" class="aligncenter size-full wp-image-1457" /></a></p>
<p><strong><a href="https://github.com/CHH/phpenv">CHH/phpenv &#8211; GitHub</a></strong></p>
<p>複数のバージョンの PHP を管理し, コマンドで簡単に切り替えるためのものです.<br />
Ruby でいう <strong><a href="https://github.com/sstephenson/rbenv">rbenv</a></strong> や <strong><a href="http://beginrescueend.com/">RVM</a></strong>, Perl でいうところの <strong><a href="http://www.perlbrew.pl/">perlbrew</a></strong> にあたるものです.</p>
<p>なお, phpenv の中身は rbenv を流用することで動いています.</p>
<p><strong>インストール</strong></p>
<p>まず, 以下のコマンドでインストールスクリプトを実行します.</p>
<pre class="brush:bash">
$ curl https://raw.github.com/CHH/phpenv/master/install.sh | sh
</pre>
<p>中では rbenv を git clone していたりするので, Git をインストールしている必要があります.</p>
<p>上記コマンドが成功したら, <strong>~/.bashrc</strong> もしくは zsh 使いなら <strong>~/.zshrc</strong> に以下のコマンドを追記します.</p>
<p>あとはいま編集したファイルを再度読み込み直すことでインストールは完了です.</p>
<pre class="brush:bash">
# bash の場合
$ source ~/.bashrc

# zsh の場合
$ source ~/.zshrc
</pre>
<pre class="brush:bash">
# phpenv
export PATH=$HOME/.phpenv/bin:$PATH
eval "$(phpenv init -)"
</pre>
<p><strong>rbenv をインストールしている場合</strong></p>
<p>先にも書きましたが, phpenv は rbenv を利用した作りになっています.<br />
その関係もあって, <strong>PATH の設定は rbenv が phpenv よりも先になっていないと, 正常に動作しません.</strong><br />
~/.bashrc や ~/.zshrc の設定は, 例えば以下のようにする必要があるので注意が必要です.</p>
<pre class="brush:bash">
# rbenv &#038; phpenv
export PATH=$HOME/.rbenv/bin:$HOME/.phpenv/bin:$PATH
eval "$(rbenv init -)"
eval "$(phpenv init -)"
</pre>
<p><strong>PHP のインストール</strong></p>
<p>phpenv は PHP の環境を管理するためのものであって, RVM や perlbrew のようにインストールするための機能はありません.<br />
その点は rbenv も同様です.</p>
<p>rbenv では ruby-build を使って Ruby をインストールしますが, phpenv では <strong><a href="https://github.com/CHH/php-build">php-build</a></strong> というツールを使うことができます.</p>
<p>php-build のインストールについては以下の記事を参考にしてください.</p>
<p><strong><a href="http://blog.yuyat.jp/archives/1376">php-build で PHP 5.4.0 beta1 をビルドする</a></strong></p>
<p>以下は php-build のインストールを済ませた, という前提で進めます.</p>
<p>phpenv で管理できるようにインストールするには, <strong>~/.phpenv/versions</strong> ディレクトリ内にサブディレクトリを作って, それぞれのバージョンの PHP をインストールする必要があるので, 以下のようにします.</p>
<pre class="brush:bash">
$ php-build 5.4.0beta2 ~/.phpenv/versions/5.4.0beta2
</pre>
<p>インストールが完了すれば phpenv の管理下に置かれることになります.</p>
<pre class="brush:bash">
$ phpenv versions
  5.4.0beta1
* 5.4.0beta2 (set by /home/yuya/.phpenv/version)
</pre>
<p><strong>使用する PHP のバージョンを切り替える</strong></p>
<p>以下のようなのコマンドで, インストール済みの PHP のバージョンを切り替えることができます.</p>
<pre class="brush:bash">
$ phpenv global 5.4.0beta2
</pre>
<p>その他, 使い方は基本的に rbenv と同様なので, そちらを参考にしてください.</p>
<p><strong><a href="https://github.com/sstephenson/rbenv">sstephenson/rbenv &#8211; GitHub</a></strong></p>
<p><strong>phpenv と php-build の連携</strong></p>
<p>php-build でのビルドでも充分に簡単ですが, せっかくなので phpenv と連携させてもっと簡単にしてみましょう.<br />
以下のようなコマンドだけで好きなバージョンの PHP をビルドし, phpenv の管理下にインストールできるようにします.</p>
<pre class="brush;bash">
$ phpenv install 5.4.0beta2
</pre>
<p>rbenv でも ruby-build と連携することで rbenv install というサブコマンドを利用することができるようになります.<br />
そこで, rbenv install するためのスクリプト rbenv-install を流用して, こんなものを用意してみました.</p>
<p><script src="https://gist.github.com/1305922.js?file=rbenv-install"></script></p>
<p>このスクリプトを <strong>~/.phpenv/libexec/rbenv-install</strong> として保存するだけでインストールは完了です.<br />
これで先のような <strong>phpenv install</strong> サブコマンドが使えるようになっています.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1446/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>スライドにシンタックスハイライトされたコードを載せる</title>
		<link>http://blog.yuyat.jp/archives/1425</link>
		<comments>http://blog.yuyat.jp/archives/1425#comments</comments>
		<pubDate>Sun, 02 Oct 2011 14:05:36 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[Gist]]></category>
		<category><![CDATA[Presentation]]></category>
		<category><![CDATA[UserScript]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1425</guid>
		<description><![CDATA[大まかな手順 Gist にコードを貼付ける UserScript を使って好きな色に変える PowerPoint なり Keynote なりにコピペする この方法で作られたのが, ひとつ前の記事のスライドです. 以下,  [...]]]></description>
			<content:encoded><![CDATA[<p><strong>大まかな手順</strong></p>
<ol>
<li>Gist にコードを貼付ける</li>
<li>UserScript を使って好きな色に変える</li>
<li>PowerPoint なり Keynote なりにコピペする</li>
</ol>
<p>この方法で作られたのが, <a href="http://blog.yuyat.jp/archives/1386">ひとつ前の記事</a>のスライドです.<br />
以下, もう少し詳しく説明します.</p>
<p><strong>Gist にコードを貼付ける</strong></p>
<p>これは特に説明いらないと思いますが, <a href="https://github.com/">GitHub</a> の <strong><a href="https://gist.github.com/">Gist</a></strong> に, スライドに掲載したいコードをコピペします.<br />
Gist ではアカウントが無くても匿名でコードを貼付けることができます.</p>
<p><strong>UserScript を使って好きな色に変える</strong></p>
<p>ここが一連の流れの中のキモです.</p>
<p>UserScript とは, Firefox であれば Greasemonkey というアドオンを使って, ページのレンダリング後にフックさせるスクリプトのことです.<br />
要は, 特定のページの表示するときに好きな JavaScript を実行させるものです.<br />
UserScript の設定についてはこの記事では説明しません.</p>
<p>なお, Google Chrome であれば UserScript は標準でサポートされています.</p>
<p>以下の UserScript は, PHP のコードのシンタックスハイライトを, ボク自身の好みに合わせて変えるためのものです.</p>
<p><script src="https://gist.github.com/1254056.js?file=paste_your_code_your_color.user.js"></script></p>
<p>Gist ではシンタックスハイライトが span タグの class で指定されています.<br />
この UserScript では, それぞれのクラスに対して自分の好きなスタイルを追加で適用しています.</p>
<p>これを使うと, Gist におけるシンタックスハイライトは以下のようになります.</p>
<div id="attachment_1429" class="wp-caption aligncenter" style="width: 423px"><a href="http://blog.yuyat.jp/archives/1425/32bf57683798729ff17e7aa6e2cf1edf" rel="attachment wp-att-1429"><img src="http://blog.yuyat.jp/wp-content/uploads/32bf57683798729ff17e7aa6e2cf1edf.png" alt="シンタックスハイライトを変更した Gist" title="シンタックスハイライトを変更した Gist" width="413" height="466" class="size-full wp-image-1429" /></a><p class="wp-caption-text">シンタックスハイライトを変更した Gist</p></div>
<p>言語によって, 指定された class は結構異なるようで, 上記の UserScript ではカバーされていない class もあります.<br />
上記はそのまま使うのではなく, それぞれの好みや言語によって作り替えるのがいいでしょう.</p>
<p><strong>PowerPoint なり Keynote なりにコピペする</strong></p>
<p>PowerPoint や Keynote は, ブラウザから文字列をコピペする際, 色や大きさといった文字の属性ごとコピーしてくれます.<br />
それ以外でも, そういった機能を持つプレゼンテーションソフトウェアであればこの方法は使えますし, そうでないものであれば使えません.</p>
<p>Gist からコードを貼付けると以下のようになります.</p>
<div id="attachment_1434" class="wp-caption aligncenter" style="width: 412px"><a href="http://blog.yuyat.jp/archives/1425/0cda462f251aaf4d3653268a7df078b3" rel="attachment wp-att-1434"><img src="http://blog.yuyat.jp/wp-content/uploads/0cda462f251aaf4d3653268a7df078b3.png" alt="コードを Keynote にコピペ" title="コードを Keynote にコピペ" width="402" height="273" class="size-full wp-image-1434" /></a><p class="wp-caption-text">コードを Keynote にコピペ</p></div>
<p>このままだと小さすぎるので, 文字サイズは適宜調節します.<br />
UserScript で予め文字を大きくしておくこともできますが, 文字の大きさはそれぞれで微調整するので, 貼付けたあとで変更するようにしました.</p>
<p><strong>問題点</strong></p>
<p>コピペ作業が多いので, コードが増えてくると結局煩雑になります.<br />
プレゼンテーションソフトウェアの中には, プレーンテキストからスライドを生成するものがあり, それらは主にエンジニア向けにデザインされているので, コードのシンタックスハイライトに対応しているものが多いです.<br />
そういう場合はそういった選択肢を考えてみるのもいいかもしれません.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1425/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第56回PHP勉強会＠関東で PHPUnit について話してきた</title>
		<link>http://blog.yuyat.jp/archives/1386</link>
		<comments>http://blog.yuyat.jp/archives/1386#comments</comments>
		<pubDate>Sun, 02 Oct 2011 11:36:30 +0000</pubDate>
		<dc:creator>yuya</dc:creator>
				<category><![CDATA[Event]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Test Driven Development]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[PHPUnit]]></category>

		<guid isPermaLink="false">http://blog.yuyat.jp/?p=1386</guid>
		<description><![CDATA[PHPUnit でのテストをよりよく書くことで, アプリケーションの設計まで改善するための方法・考え方についてまとめました.]]></description>
			<content:encoded><![CDATA[<div style="width:425px" id="__ss_9494860"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/taketyan/phpunit-9494860" title="PHPUnit でよりよくテストを書くために" target="_blank">PHPUnit でよりよくテストを書くために</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/9494860" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/taketyan" target="_blank">Yuya Takeyama</a> </div>
</p></div>
<p>最近 HTML5 化した Slideshare ですが, エラーで表示できないスライドが多すぎてまともに閲覧できないようです.<br />
この記事に掲載している Flash 版は今まで通りの問題なく表示できるのですが&#8230;</p>
<p>スライドが完成したのが勉強会への出発 15 分前で, 通しで練習することすらできず, 発表はかなりひどいものとなっていまいました.<br />
最低限, スライドの流れぐらいは頭の中に入れて発表すべきですね…</p>
<p>スライドだけ見てわかるような作りにはなっていないので, 以下で補足したいと思います.<br />
ただし, 序盤は省略し, 本論となる書法編とパターン編についてのみとなります.</p>
<p>それぞれ該当するスライド番号も付記してありますので, よければご活用ください.</p>
<p><strong>書法編 1: ヘルパーメソッドを使う (25 ~ 30)</strong></p>
<p>テスト対象のオブジェクト, それを生成するのに必要な依存オブジェクトの生成には, <strong>ヘルパーメソッド</strong>の使用を検討しましょう.<br />
new するだけで済むものであればそれでもいいのですが, <strong>生成に複雑なステップを踏む必要がある場合</strong>に威力を発揮します.</p>
<p>これは一般的なプログラミングにおけるサブルーチンみたいなものだと思って問題無いと思います.<br />
ただし, <strong>可読性</strong>を問題にするのであれば, 多少長くても<strong>説明的でわかりやすいメソッドの命名</strong>を心がける必要があります.</p>
<p>テスト対象の生成が複雑だと, 複数のテストの比較が大変になります.<br />
ヘルパーメソッドを使うことで, テスト A とテスト B はどこに<strong>有意な違い</strong>が有り, 結果に違いが生まれるのか, ということがわかりやすくなります.</p>
<p>書籍 <strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/0131495054/yuyat-22/">xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler))</a></span></em></strong> では, Fixture Setup Patterns において <strong>Creation Method</strong> という名前で紹介されています.<br />
また, これの応用として, 引数付きの <strong>Parameterized Creation Method</strong> というものも紹介されています.</p>
<p><strong>書法編 2: テストメソッドを分割する (31 ~ 36)</strong></p>
<p>ひとつのテストメソッド内で, いろんなことをテストしようとすると, <strong>何をテストしようとしているのか</strong>がわかりにくくなります.<br />
例え同じメソッドを対象にしたテストであっても, 前提条件等が違うのであれば, <strong>分割</strong>するべきです.</p>
<p>分割することで, それぞれのテストメソッドには, より<strong>具体的な名前</strong>をつけることができます.<br />
これもまた可読性に寄与すると言えるでしょう.</p>
<p>これは癖のレベルの話なので, 普段からテストを書いている人であれば無意識にそうなると思います.<br />
まずは 1 つのテストメソッドにおいて<strong>アサーションは 1 つまで</strong>, というルールを課すことで自然とそういう書き方に近づくと思います.</p>
<p><strong>パターン編 1: 依存性は外から差し込む (39 ~ 49)</strong></p>
<p>スライドでは, フレームワークによくある Request クラスを例に, $_SERVER といったスーパーグローバル変数を使ったときに起こる問題について説明しました.</p>
<p>$_SERVER を使った実装でもちゃんと動作するので, 問題と見なさないこともできます.<br />
しかし, 問題はテストを書こうとしたときに顕在化します.</p>
<p>スーパーグローバル変数に限らず, グローバル変数を利用した実装だと, <strong>複数のテストが影響し合う</strong>可能性が生まれます.<br />
スライドではコードで例示しているので, 具体的にはスライドの該当箇所を参照してください.<br />
スライドのように unset($_SERVER['HTTPS']) とすることで回避できますが, コードベースが巨大化すると, <strong>暗黙的なコンテキストが肥大化</strong>し, テストを書くのがだんだんと困難になります.</p>
<p>その代わりにどうするのかというと, スーパーグローバル変数 $_SERVER を直接参照するのではなく, コンストラクタやセッターメソッド等で, <strong>引数として差し込む</strong>, という方法を採ります.<br />
<strong>Dependency Injection (DI, 依存性の注入)</strong> というパターンです.<br />
DI を採用することで, <strong>再利用性</strong>が高くなるので, テストを書くことで設計が向上する例としては比較的よく挙げられます.</p>
<p><strong>パターン編 2: 外部への依存を避ける (50 ~ 62)</strong></p>
<p>ひとつ前の話を逆に言っているだけですが, 別の側面から解説しています.</p>
<p>外部への依存としては, 例えば以下のようなものが挙げられます.</p>
<ul>
<li>グローバル変数/スーパーグローバル変数</li>
<li>ファイルシステム</li>
<li>Web API やデータベース等のネットワーク</li>
</ul>
<p>しかし, もちろんこれらを完全に避けてのアプリケーション開発は考えられません.<br />
それではどうするのか, ということで, スライドでは <strong>Active Record</strong> の問題点と, それを解決したパターンとしての <strong>Data Mapper</strong> を例に説明しています.</p>
<p>ここでいう Active Record というのはパターンとしての Active Record で, 書籍 <strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/0321127420/yuyat-22/">Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))</a></span></em></strong> で紹介されています.<br />
Ruby on Rails の ORM としての ActiveRecord は, それを実装したものです.</p>
<p>Active Record においては, 1 つのレコードが 1 つのオブジェクトにマッピングされ, それぞれの<strong>レコードはデータベースを知っています</strong>.<br />
なので, $record->save() といった操作が可能になります.</p>
<p><strong>Data Mapper</strong> でも 1 つのレコードが 1 つのオブジェクトに, という部分は変わりませんが, それぞれの<strong>レコードはデータベースのことを知りません</strong>.<br />
例えば users というテーブルであれば, User クラスがその 1 レコードを表し, UserMapper はテーブルを表します.<br />
(実際にはテーブルをラップしたクラスとして実装されることが多いと思いますが, ここでは単純化しています)<br />
レコードはデータベースのことを知らないので, レコードを保存する際は $mapper->save($record) といったようにする必要があります.</p>
<p>それでは Active Record の何が問題なのか.<br />
Active Record ではレコードが<strong>ドメインロジック (ビジネスロジック) を持ったドメインオブジェクト</strong>としての側面と, <strong>データアクセスを行うオブジェクト</strong>としての側面を持つことになります.<br />
それぞれは全く違った関心事なので, <strong>関心事の分離 (SoC)</strong> や<strong>単一責任原則 (SRP)</strong> といったソフトウェア開発の原則に違反することになります.<br />
テストに関していうと, <strong>データベースへのアクセス無しにドメインロジックをテストできない</strong>, といったことが起こりやすくなります.<br />
(もちろん, 実装によりますが)</p>
<p>逆に <strong>Data Mapper</strong> ではドメインロジック (上の例でいうと User クラス) を<strong>データベース無しでテストできます</strong>.<br />
データベースに対してテストを書きたいときもありますし, そのためのテクニックもいろいろとありますが, まずはそれらを無視してテストできるような<strong>クラス分割</strong>を行うことで, 低コストで確実にテストを書くことができます.</p>
<p><strong>パターン編 3: Singleton を避ける (63 ~ 71)</strong></p>
<p>Singleton は GoF のデザインパターンの中では最も理解しやいもののひとつで, よく使われるパターンのひとつです.<br />
しかし, 同時に批判的意見の多いパターンでもあります.</p>
<p>Singleton ではクラスの static プロパティとしてオブジェクトとその状態がグローバル空間に残ってしまいます.<br />
これはつまり, <strong>グローバル変数と同様の性質を持っている</strong>, ということができます.</p>
<p>また, グローバル変数と違って, <strong>容易に上書くこともできない</strong>ので, テストをする上ではさらに厄介な存在といえます.</p>
<p>対策としては以下が考えられます.</p>
<ul>
<li>状態を初期化するためのメソッドを用意する</li>
<li>アプリケーション本体では getInstance() といった, 常に同一のインスタンスを取得するメソッドの使用を規約化し, テストでは new でそれぞれ独立したオブジェクトを生成し, テストする</li>
</ul>
<p>また, PHPUnit にはこれらを回避するための <strong>&#8211;process-isolation オプション</strong>であったり, <strong>@runTestsInSeparateProcesses アノテーション</strong>といった機能もあるのですが, それらについては説明しませんでした.<br />
Singleton を使わなければ, これらの機能について理解する必要もなくなりますし, これらは <strong>Slow Test (テストの実行が遅くなる) 問題</strong>を引き起こします.</p>
<p>Singleton で実装したくなったとき, <strong>本当に Singleton である必要があるのか</strong>については, 一度考えてみる必要があるでしょう.</p>
<p><strong>参考文献</strong></p>
<p>スライド中に挙げたものです.<br />
書籍へのリンクにはアフィリエイトタグをつけています.</p>
<ul>
<li><strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/0131495054/yuyat-22/"><img src="http://ecx.images-amazon.com/images/I/41gw3-DOWrL._SL160_.jpg" />xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler))</a></span></em></strong><br />
xUnit とというのは SUnit (Smalltalk), JUnit (Java) といったナントカ Unit 系テスティングフレームの総称です.<br />
例として示されるコードは Java のものが多めですが, PHPUnit も書き方を含めて xUnit と呼べるものなので, この書籍で挙げられている考え方やテクニックは, ほぼそのまま適用できます.<br />
鈍器として人を殺せる程の分量がありますが, 気になるトピックをつまみ食いすることもできます.</li>
<li><strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/0470872497/yuyat-22/"><img src="http://ecx.images-amazon.com/images/I/51-b3XXNMAL._SL160_.jpg" />Real-World Solutions for Developing High-Quality PHP Frameworks and Applications</a></span></em></strong><br />
PHPUnit の作者 <strong><em>Sebastian Bergmann</em></strong> を初めとする豪華な著者陣による, PHP アプリケーションの品質, テスト, 設計についての書籍.<br />
Symfony の作者 <strong><em>Fabien Potencier</em></strong> による章もあります.<br />
ソフトウェアの品質についての解説などは他の PHP 本にはまず無いものですし, 非常に刺激的な 1 册です.</li>
<li><strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/0321127420/yuyat-22/"><img src="http://ecx.images-amazon.com/images/I/511D6FdsbXL._SL160_.jpg" />Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))</a></span></em></strong><br />
アプリケーションのアーキテクチャパターンについての書籍.<br />
全体的な分量からするとほとんど読めていないのですが, スライド中の Active Record や Data Mapper について参考にしました.</li>
<li><strong><em><span class="isbn_anchor"><a href="http://www.amazon.co.jp/o/ASIN/4798015164/yuyat-22/"><img src="http://ecx.images-amazon.com/images/I/51BFWSV4WTL._SL160_.jpg" />PHPによるデザインパターン入門</a></span></em></strong><br />
GoF によるデザインパターンを PHP に翻訳して紹介している書籍.<br />
新卒の頃に読んで衝撃を受けました.<br />
残念ながら絶版なので買うことはできませんが, <a href="http://www.doyouphp.jp/book/book_phpdp.shtml">原稿が公開されている</a>ので, 読むことはできます.<br />
是非電子書籍化して欲しい 1 冊です.</li>
</ul>
<p>こちらはスライドです.</p>
<ul>
<li><strong><a href="http://www.slideshare.net/fabpot/dependency-injection-with-php-53">Dependency Injection with PHP 5. 3</a></strong><br />
 Symfony の作者 <strong><em>Fabien Potencier</em></strong> によるスライド.<br />
序盤は Dependency Injection の基礎についての説明で, そのあとに PHP 5.3 における DI コンテナの実装について説明しています.</li>
<li><strong><a href="http://www.slideshare.net/akihito.koriyama/bear-di">BEAR DI</a></strong><br />
リソース指向のフレームワーク <a href="http://code.google.com/p/bear-project/">BEAR</a> の作者の <a href="http://twitter.com/koriym"><strong>@koriym</strong></a> さんによるスライド.<br />
序盤は前のスライドを日本語訳しつつ引用し, 後半では BEAR の DI コンテナについて説明しています.</li>
<li><strong><a href="http://www.slideshare.net/sebastian_bergmann/clean-php-dpc11">Clean PHP</a></strong><br />
PHPUnit の作者 <strong><em>Sebastian Bergmann</em></strong> によるスライド.<br />
これだけ見て何かを理解するのには向きませんが, Active Record と Data Mapper の比較についてはこれを参考にしました.</li>
<li><strong><a href="http://www.slideshare.net/go_oh/singletons-in-php-why-they-are-bad-and-how-you-can-eliminate-them-from-your-applications">Singletons in PHP &#8211; Why they are bad and how you can eliminate them from your applications</a></strong><br />
 Singleton の問題点について, 詳細に説明されています.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.yuyat.jp/archives/1386/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

