最近 HTML5 化した Slideshare ですが, エラーで表示できないスライドが多すぎてまともに閲覧できないようです.
この記事に掲載している Flash 版は今まで通りの問題なく表示できるのですが…

スライドが完成したのが勉強会への出発 15 分前で, 通しで練習することすらできず, 発表はかなりひどいものとなっていまいました.
最低限, スライドの流れぐらいは頭の中に入れて発表すべきですね…

スライドだけ見てわかるような作りにはなっていないので, 以下で補足したいと思います.
ただし, 序盤は省略し, 本論となる書法編とパターン編についてのみとなります.

それぞれ該当するスライド番号も付記してありますので, よければご活用ください.

書法編 1: ヘルパーメソッドを使う (25 ~ 30)

テスト対象のオブジェクト, それを生成するのに必要な依存オブジェクトの生成には, ヘルパーメソッドの使用を検討しましょう.
new するだけで済むものであればそれでもいいのですが, 生成に複雑なステップを踏む必要がある場合に威力を発揮します.

これは一般的なプログラミングにおけるサブルーチンみたいなものだと思って問題無いと思います.
ただし, 可読性を問題にするのであれば, 多少長くても説明的でわかりやすいメソッドの命名を心がける必要があります.

テスト対象の生成が複雑だと, 複数のテストの比較が大変になります.
ヘルパーメソッドを使うことで, テスト A とテスト B はどこに有意な違いが有り, 結果に違いが生まれるのか, ということがわかりやすくなります.

書籍 xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler)) では, Fixture Setup Patterns において Creation Method という名前で紹介されています.
また, これの応用として, 引数付きの Parameterized Creation Method というものも紹介されています.

書法編 2: テストメソッドを分割する (31 ~ 36)

ひとつのテストメソッド内で, いろんなことをテストしようとすると, 何をテストしようとしているのかがわかりにくくなります.
例え同じメソッドを対象にしたテストであっても, 前提条件等が違うのであれば, 分割するべきです.

分割することで, それぞれのテストメソッドには, より具体的な名前をつけることができます.
これもまた可読性に寄与すると言えるでしょう.

これは癖のレベルの話なので, 普段からテストを書いている人であれば無意識にそうなると思います.
まずは 1 つのテストメソッドにおいてアサーションは 1 つまで, というルールを課すことで自然とそういう書き方に近づくと思います.

パターン編 1: 依存性は外から差し込む (39 ~ 49)

スライドでは, フレームワークによくある Request クラスを例に, $_SERVER といったスーパーグローバル変数を使ったときに起こる問題について説明しました.

$_SERVER を使った実装でもちゃんと動作するので, 問題と見なさないこともできます.
しかし, 問題はテストを書こうとしたときに顕在化します.

スーパーグローバル変数に限らず, グローバル変数を利用した実装だと, 複数のテストが影響し合う可能性が生まれます.
スライドではコードで例示しているので, 具体的にはスライドの該当箇所を参照してください.
スライドのように unset($_SERVER['HTTPS']) とすることで回避できますが, コードベースが巨大化すると, 暗黙的なコンテキストが肥大化し, テストを書くのがだんだんと困難になります.

その代わりにどうするのかというと, スーパーグローバル変数 $_SERVER を直接参照するのではなく, コンストラクタやセッターメソッド等で, 引数として差し込む, という方法を採ります.
Dependency Injection (DI, 依存性の注入) というパターンです.
DI を採用することで, 再利用性が高くなるので, テストを書くことで設計が向上する例としては比較的よく挙げられます.

パターン編 2: 外部への依存を避ける (50 ~ 62)

ひとつ前の話を逆に言っているだけですが, 別の側面から解説しています.

外部への依存としては, 例えば以下のようなものが挙げられます.

  • グローバル変数/スーパーグローバル変数
  • ファイルシステム
  • Web API やデータベース等のネットワーク

しかし, もちろんこれらを完全に避けてのアプリケーション開発は考えられません.
それではどうするのか, ということで, スライドでは Active Record の問題点と, それを解決したパターンとしての Data Mapper を例に説明しています.

ここでいう Active Record というのはパターンとしての Active Record で, 書籍 Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler)) で紹介されています.
Ruby on Rails の ORM としての ActiveRecord は, それを実装したものです.

Active Record においては, 1 つのレコードが 1 つのオブジェクトにマッピングされ, それぞれのレコードはデータベースを知っています.
なので, $record->save() といった操作が可能になります.

Data Mapper でも 1 つのレコードが 1 つのオブジェクトに, という部分は変わりませんが, それぞれのレコードはデータベースのことを知りません.
例えば users というテーブルであれば, User クラスがその 1 レコードを表し, UserMapper はテーブルを表します.
(実際にはテーブルをラップしたクラスとして実装されることが多いと思いますが, ここでは単純化しています)
レコードはデータベースのことを知らないので, レコードを保存する際は $mapper->save($record) といったようにする必要があります.

それでは Active Record の何が問題なのか.
Active Record ではレコードがドメインロジック (ビジネスロジック) を持ったドメインオブジェクトとしての側面と, データアクセスを行うオブジェクトとしての側面を持つことになります.
それぞれは全く違った関心事なので, 関心事の分離 (SoC)単一責任原則 (SRP) といったソフトウェア開発の原則に違反することになります.
テストに関していうと, データベースへのアクセス無しにドメインロジックをテストできない, といったことが起こりやすくなります.
(もちろん, 実装によりますが)

逆に Data Mapper ではドメインロジック (上の例でいうと User クラス) をデータベース無しでテストできます.
データベースに対してテストを書きたいときもありますし, そのためのテクニックもいろいろとありますが, まずはそれらを無視してテストできるようなクラス分割を行うことで, 低コストで確実にテストを書くことができます.

パターン編 3: Singleton を避ける (63 ~ 71)

Singleton は GoF のデザインパターンの中では最も理解しやいもののひとつで, よく使われるパターンのひとつです.
しかし, 同時に批判的意見の多いパターンでもあります.

Singleton ではクラスの static プロパティとしてオブジェクトとその状態がグローバル空間に残ってしまいます.
これはつまり, グローバル変数と同様の性質を持っている, ということができます.

また, グローバル変数と違って, 容易に上書くこともできないので, テストをする上ではさらに厄介な存在といえます.

対策としては以下が考えられます.

  • 状態を初期化するためのメソッドを用意する
  • アプリケーション本体では getInstance() といった, 常に同一のインスタンスを取得するメソッドの使用を規約化し, テストでは new でそれぞれ独立したオブジェクトを生成し, テストする

また, PHPUnit にはこれらを回避するための –process-isolation オプションであったり, @runTestsInSeparateProcesses アノテーションといった機能もあるのですが, それらについては説明しませんでした.
Singleton を使わなければ, これらの機能について理解する必要もなくなりますし, これらは Slow Test (テストの実行が遅くなる) 問題を引き起こします.

Singleton で実装したくなったとき, 本当に Singleton である必要があるのかについては, 一度考えてみる必要があるでしょう.

参考文献

スライド中に挙げたものです.
書籍へのリンクにはアフィリエイトタグをつけています.

  • xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler))
    xUnit とというのは SUnit (Smalltalk), JUnit (Java) といったナントカ Unit 系テスティングフレームの総称です.
    例として示されるコードは Java のものが多めですが, PHPUnit も書き方を含めて xUnit と呼べるものなので, この書籍で挙げられている考え方やテクニックは, ほぼそのまま適用できます.
    鈍器として人を殺せる程の分量がありますが, 気になるトピックをつまみ食いすることもできます.
  • Real-World Solutions for Developing High-Quality PHP Frameworks and Applications
    PHPUnit の作者 Sebastian Bergmann を初めとする豪華な著者陣による, PHP アプリケーションの品質, テスト, 設計についての書籍.
    Symfony の作者 Fabien Potencier による章もあります.
    ソフトウェアの品質についての解説などは他の PHP 本にはまず無いものですし, 非常に刺激的な 1 册です.
  • Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler))
    アプリケーションのアーキテクチャパターンについての書籍.
    全体的な分量からするとほとんど読めていないのですが, スライド中の Active Record や Data Mapper について参考にしました.
  • PHPによるデザインパターン入門
    GoF によるデザインパターンを PHP に翻訳して紹介している書籍.
    新卒の頃に読んで衝撃を受けました.
    残念ながら絶版なので買うことはできませんが, 原稿が公開されているので, 読むことはできます.
    是非電子書籍化して欲しい 1 冊です.

こちらはスライドです.

  • Dependency Injection with PHP 5. 3
    
Symfony の作者 Fabien Potencier によるスライド.
    序盤は Dependency Injection の基礎についての説明で, そのあとに PHP 5.3 における DI コンテナの実装について説明しています.
  • BEAR DI
    リソース指向のフレームワーク BEAR の作者の @koriym さんによるスライド.
    序盤は前のスライドを日本語訳しつつ引用し, 後半では BEAR の DI コンテナについて説明しています.
  • Clean PHP
    PHPUnit の作者 Sebastian Bergmann によるスライド.
    これだけ見て何かを理解するのには向きませんが, Active Record と Data Mapper の比較についてはこれを参考にしました.
  • Singletons in PHP – Why they are bad and how you can eliminate them from your applications
    
Singleton の問題点について, 詳細に説明されています.
,

皆さん, ユニットテスト書いてますか.

TDD (テスト駆動開発) によるプログラミングは本当に楽しいものですが, コマンドをいちいち手動で実行するのは面倒ですよね.
テストを自動化しているんだから, その実行も自動化したいですよね.

この記事では, 私が仕事や趣味で使っている PHPUnit を例に, テストの実行の自動化について紹介します.
PHPUnit の, としてはいますが, 他の言語で使えるテクニックもあります.

なお, ここでの自動化は開発しながらの自動実行のことで, CI (継続的インテグレーション) の話は出てきません.

その前に…

私の開発時のターミナルは以下のようになっています.

開発時のターミナル

開発時のターミナル

GNU screen での画面分割を利用して, 左半分をソースコードに, 右上をテストコードに, 右下をテストの実行に使っています.
これは作業の途中でいろいろと変動しますが, 右下ではほぼ常にテストが自動実行されるようになっています.
(ターミナルの透明化を利用してバックグラウンドでニコ動を観ることもできますね)

この小さい画面での実行を前提に, 紹介していきます.

シェルスクリプトを利用する

まずはとにかく, 決められたコマンドを定期的に実行しましょう.

コマンドを定期的に実行, というと watch コマンドを思い浮かべる人が多いと思いますが, これは使いません.
何故か, ターミナル上の色が無効化されてしまい, レッドやグリーンがわかりづらいからです.

色の使える watch は無いか, と探した所, superuser という Q&A サイトにちょうどいいものがありました.
bash watch command with colors preserved

ここへの書き込みを参考に, 以下のようなシェルスクリプトを用意しました.

適当な場所に保存して, chmod +x して実行権限を与えたら, 以下のように使用することができます.

$ ./watch2 phpunit --colors

これで, 出力の色づけを維持したまま, PHPUnit を 2 秒間のインターバルで起動し続けることができるようになりました.

プロジェクトの規模によっては全てのテストを実行するのに時間がかかることもあるので, そういうときは特定のファイルを指定しましょう.

$ ./watch2 phpunit --colors tests/Foo/BarTest.php

今自分が作業しているファイルだけを指定することで, フィードバックを素早く的確に得られるようになります.
コマンドの指定は手動ですが, 環境の用意はとても楽なのでよしとしましょう.

Stagehand_TestRunner を利用する

Stagehand_TestRunner は, PHPUnit だけでなく Lime や PHPSpec にも対応したテストランナーです.
(2011-08-16 14:00 追記: Lime への対応は勘違いでした. @heavenshell さんご指摘ありがとうございました.)

インストールについては本家の Wiki を参照しましょう.
テスト駆動開発のためのテストランナー

PHPUnit 本家よりも優れた表示が特徴です.

Stagehand_TestRunner による実行結果

Stagehand_TestRunner による実行結果

この出力形式は testdox と呼ばれるもので, テストメソッド名を英文っぽく表示してくれます.
testdox を表示する機能自体は PHPUnit にもあります (--testdox オプション) が, Stagehand_TestRunner を使うと色づけされるので, よりわかりやすくなります.

Stagehand_TestRunner には他にも様々な機能がありますが, ここで紹介するのはディレクトリの監視によるテストの自動実行です.

これを phpunit.xml として保存して, 同じディレクトリ上で以下のコマンドを実行します.

$ phpunitrunner --phpunit-config=phpunit.xml -cRa

c が色づけ, R が指定ディレクトリ (phpunit.xml で指定していますね) 以下を再帰的に, a が自動実行のためのオプションです.

これで, ディレクトリに変更のあったときだけテストが実行されるようになりました.

実行対象のテストを正規表現で絞り込んだりすることもできますが, それらの詳細については以下の Wiki が参考になります.
Stagehand_TestRunner ユーザーガイド

watchr を利用する

最後に紹介するのは, 最近一番よく使っている方法です.
watchr はファイルの変更を監視するツールで, 検出時にあらゆる処理をフックさせることができます.

watchr は Ruby 製のツールなので, 処理は Ruby で書く必要があります.
といっても, 簡単な正規表現が書ければ充分なので, Ruby 未経験でも問題無いでしょう.

インストールについては Rubygems をインストールして gem install watchr するだけです.

watchr の設定ファイルとして, 以下のようなものを用意します.

これは src ディレクトリのソースコードの変更時に対応するテストを実行すること, テストコードの変更時にはそのファイル自身のテストを実行すること, を設定しています.

そして以下のようなコマンドを実行することで, 監視状態に入ります.

$ watchr phpunitrunner.watchr

前提として, ソースコードが src/Foo.php であればテストコードは tests/FooTest.php というように, 命名規則にそったファイル名になっていることが必要です.

変更のあったときにだけ, そのファイルだけテストが実行されるので, 素早く確実にフィードバックを得ることができます.

また, Ctrl + \ を押すことで, 全てのテストを実行することもできます.

注意としては, 監視対象のファイルの読み込みが watchr の起動時なので, 例えば途中で新規に追加したファイルは監視対象に入っていないことです.
ある程度開発が進んで, 作業のメインが既存ファイルの編集になったときに, より高い効果を発揮するでしょう.

まとめ

テストだけでなく, その実行まで自動化することで開発にリズムが生まれ, フロー状態に入りやすくなります.
開発効率を上げ, 楽しい TDD ライフを送りましょう.

その他, オススメのツールややり方などありましたら, 是非 @yuya_takeyama まで教えてください.

, , , ,

最後の日本 RubyKaigi です.
出張の関係で 2 日目の終盤からしか参加できていませんが, 印象に残ったものを簡単にまとめてみました.

Advancing Net::HTTP by @wycats さん

* net/http は並列化できない
* 並列化するためにフォークして net2/http というのを作っている
* 並列化するにあたって Reactor パターンを採用した

ergをすごく偲んで by @m_seki さん

* カスタマイズは誘惑する
* 安易にオプションを増やすことは「仕様の議論からの逃避」

Visual Glitch, using Ruby by @ucnv さん

* とっさにグリッチが必要なときは sed が便利
* チェックサムを壊したりすると表示自体できなくなることがある
* 安全にグリッチするにはどうするか
* 仕様に従って壊すのがマナー
* 動画はキーフレームを抜くことでいい感じに壊せる

ネタ的な発表かと思いましたが, 技術的には思いのほか真摯であり, とても参考になりました.
発表者の方は GitHub に aviglitch というライブラリを後悔されていますが, API, ドキュメント, spec など, あらゆる面で well-mannered な印象です.
純粋に, Ruby でカジュアルに低レベルなバイナリ操作をする上で参考になりそうです.

Ruby遺産とレガシーコード修理技術 by @hsbt さん

* tDiary のコミッタ
* tDiary は 25 年使われる予定
* 既に 10 年使われている
* 各レイヤごとのテスト
** ユニットテスト
** エンドツーエンドテスト
** インテグレーションテスト
* 機能の追加は慎重に削除は大胆に
** プログラマが知るべき97のことにおける @miyagawa さんの言葉
* 継続的インテグレーション
** travis-ci を使えば GitHub リポジトリで CI できる

長期にわたってソフトウェアを育ててきた経験に基づく, 実践的なお話.
機能の追加に慎重になる, というのは, 特に業務だといろいろなしがらみがあって難しいけど, 常に意識して行きたいものです.
No と言える力重要.

O/R Mapper を支える技術 by @makotokuwata さん

* プログラミング言語の機能は分解, 結合, 抽象化
* SQL にはそれらが欠けている
* それらを補完するのが O/R Mapper
* Ruby で SQL を組み立てること自体は抽象化ではない
* named_scope で抽象化しよう
* プログラミング言語の進化は抽象化機能の進化
* モダンな O/R Mapper の機能
** QueryObject の操作
** Collection のように振る舞うこと
** SQL の抽象化
* N + 1 問題
** DataMapper の Eager loading はうまくやっている

去年ぐらいから仕事で O/R Mapper 的なものを PHP で実装していることもあり, 実装寄りの話では一番参考になりました.
スピーカーの桑田さんのお話は去年の Kwartz についてのものもそうでしたが, 洞察に溢れているだけでなく, 非常に明瞭でわかりやすく, とにかく引きつけられました.

まとめ

昨年から引き続き参加しましたが, レベルの高い技術者の考えに触れることができ, 多いに刺激を受けました.
また, 英語を使いこなし, 海外からの参加者と対等にコミュニケーションを取っている方も多く, その店でも自らの力不足を実感させられました.

スピーカー, スタッフ, 参加者の皆様, お疲れさまでした!

,