「The Rspec Book: Behaviour Driven Development With Rspec, Cucumber, and Friends」という本。
この本は、RspecとCucumberを使い、どう考え、どうシステムを作っていくか、というをチュートリアルを交えながら紹介する構成になっている。
ただUnit Testを紹介するだけではなく、Unit TestツールであるRspecに、BDDツールであるCucumberを組み合わせて使うことで、Unit Testでカバーできない部分をCucumberで補い開発をする、というところがこの本の肝になっている。
この本を読み、実践することで、Unit Test*だけ*を書いてシステムを作っているときのモヤモヤ感をかなり解消できる。また、RspecもCucumberも知っているけど、両方をどうやって使っていくかよくわからない、という人もこの本を読むとかなりすっきりできるのでお勧め。
以下に、自分なりに理解したところを書いておく。本の内容から少し離れているところもあるので、詳しくは本を読んでみて欲しい。
また、ここでは触れないが、この本では、RspecとCucumberの基本的な使い方や、webratやseleniumなどのWeb系のテストツールと一緒に使う方法や、Railsとの組み合わせ方なども含まれているので、Rubyでのテストに関するかなりの部分がカバーされていてかなりお得な作りになっている。
Unit Testとは
改めて書くまでもなく、Unit Testというのは(自動化するかどうかは関係なく)、とにかくコンポーネントとしての精度を高めるものである。また、Unit Testの優れている点として、Unit Testは「テスト」だけのためではなく、「設計」のためであるということが言える。テストを書くということ自体が設計となる。テストが書きにくい=設計が悪い、ということでもあるので、テストをきれいに書くことで、自然といい設計になるように導いてくれる。
しかし、Unit Testは、コンポーネント単位での動作は保証するが、それらを組み合わせたときに、最終的にシステムがどのような物になるか、ということまでは基本的保証しない。そして、Unit Testは、基本的にプログラマの自作自演ということもあり、外部から、システムとして見たときにどう動くかということも保証しない。また、非エンジニアの人にどういうシステムか、というのを説明するのにもUnit Testは向いていない。
これらは別にUnit Testの欠点というわけではなくて、Unit Testはそういうものなのである。
「Unit Testだけ」で開発するモヤモヤ
Unit Testでカバーできる範囲は「設計」を設計としてそのままコードに落とし、そしてそれがそのままテストにもなり、自動化もでき、再利用もできる。
しかし、Unit Testの対象外である、システムを外部から見たときの振る舞いに関して、設計やテストはコード化されずに、BTSや色々なツールで管理しても、結局「使い捨て」になりやすい。ドキュメントをコードとは別に書いても、プロジェクトが進むごとにコードとどんどん乖離していってしまう。
今まで、この部分を解消するためにいろいろなツールやプラクティスを試してみたが、どうも自分的にしっくりくるのがなかった。それは、おそらく、そういうものの多くは、ドキュメント(紙)ベースなものが多いからだと思っている。やはりプログラマとしては、そこも「コード」で定義したいし、コードに書いてあることをドキュメントにも書くということはしたくない。
Cucumberとは
このモヤモヤを解決してくるのがCucumberというツールと、それを使ったプラクティスになる。Cucumberでは、外側の設計(とテスト)をコードに落とすものである。Cucumberを使うと、ユーザから見た動作に関しての設計を、そのままコードにすることができる。Unit Testでコンポーネントに対してテストを書くのと同じ構図になる。
また、Cucumberは非常に自然言語に近い形で書けるので、非エンジニアの人が読むことが(場合によっては書くことも)可能だ。
RspecとCucumberの連携
RspecとCucumberは、それぞれ単体で使っても、もちろん便利なのだが、この本では、それらを組み合わせることで、さらに強固で柔軟なシステムを作ることができると説明している。
コンポーネントレベルでの動作の保証にはRspecを使い、ユーザから見た動作に関しての保証にはCucumberを使うということになる。
この本では、1つの機能毎に下記の各フェーズを繰り返し開発を進めて行くことを提案している。
- Cucumberを使い外部の設計(=テスト)を書く - この段階では実装がないのでCucumberに実行結果はRed(失敗)になる。
- Rspecを使い内部の設計(=テスト)をする - この段階では実装がないのでRspecを実行するとRedになる。
- Rspecが通るように実装する。この時点でRspecはGreen(成功)になる。
- Cucumberが通るようにCucumberの実装を書く。ここで、2-3で作った部分がうまく1.の設計にあわない場合、2.に戻る必要がある。場合によっては1.に戻る。
つまり、外側 (Red) - 内側 (Red) - 内側 (Green) - 外側 (Green) という順序で開発して行くことになる。
この手法は、非常にアジャイル開発とも相性がいい。上記の1から4の一回で作る機能の単位として、アジャイルの一つのユーザストーリはぴったり当てはまる。
本の入手方法
ここまで書いておいてなんなんだが、まだこの本は紙の本としては発売されてない。延期につぐ延期で、次の予定は2010/4になっている。しかしとりあえず現時点ではベータ版をPDFで買うことができる。上のリンクから買える。
一度購入しておくと、新しいベータ版が出る度にダウンロードできるので、個人的にはここ半年位楽しんでいる。英語だが、チュートリアル形式でコードも多いので英語にあまり自信がなくてもなんとかなるだろう。
Amazon日本でも紙の本の予約はできるみたい。
クエリのところは、やっぱり読み物として面白くないな。早く終わらせてもっとMongoDBっぽいところをやりたい。
MongoDBの翻訳全般については、 こちら参照。
これとこれの続き。この後、もう少し調査して、Resqueを実際のシステムの一部で使い始めてみたのでその感想とメモ。
前回までのあらすじ
Resqueはバックグラウンドでジョブの実行をするもので、かなりの大規模サイトでかつ更新系の処理が多そうなシステムであるGithubで開発され使われている。よくある使い方としては、「Web UIを軽く見せるため、処理の依頼だけを受け付け、実際の処理はバックグラウンドで実行」「バッチ処理などで、大量のJobをQueueに突っ込んでおいて、(複数の)workerで並列で効率よく処理」などがある。
不安なところ
Resqueの大きな特徴は、QueueをRDBMSではなくRedis上に作るところにある。Redisは、Memcacheのようにシンプルに使え、すべてのデータはメモリ上に展開されるのでとても速く、データはディスク上にも永続化されるので、何かあったときにもMemcacheと違いデータが揮発しないのが特徴のkey-value型のデータベース。
今回Resqueを導入したWebシステムは、よくあるRDBMSを使ったものなので、Resqueのために新たに別な種類のデータベースを導入することへの躊躇いが多少あった。サーバ設定の手間も増えるし、各開発者の開発環境のセットアップの手間も増える。また、常時使うデータベースのようなものが一つふえると言うことはメンテナンスや障害時の手間も増える。また、RDBMSならすぐ中を確認できるが、Queueの状況が見づらいのではないか、と言った心配もある。
正直なところ、上記の不安はまだ全部それなりに残っている。が、魅力も見えてきたのでとりあえず使ってみることにした。実際に使ってみないとわからないこともあるしね。
良さそうなところ
上記のような不安がある中で、導入に踏み切った大きな理由として、QueueをRDBMSに置かずにRedisに置く、というのが実際の運用ではかなり良さそうというのがある。
メインで使っているRDBMSと同じところにQueueを置くと、RDBMSの影響をモロに受けてしまう。せっかく重い処理をバックグラウンドでするためにResqueを使っても、そのQueueの登録部分が重くなってしまっては意味がない。Queueの部分が別DB(Redis)だとこの辺のことに影響されず「とりあえずQueueに入れる」「後はサーバの状況に合わせQueueを順番に処理する」といったことができるようになる。
後は、Resque自体の作りが非常に良さそう。例えば、 convention over configuration な感じがよくできていて、新しいQueueやJobを作るときにあまり難しいことを考えずに、Rubyのコードを書くだけで済む。
Deployに関して
Resqueには、起動スクリプトのようなものが添付されていないので、何か自分で起動させる方法を考えないといけない。Githubではgodを使っているようだ。今回うちでは普段使っているCapistranoとMonitを組み合わせてDeploy時に(再)起動とプロセスの監視をすることにした。また、Resque(のworker)は、自分のプロセスとしてRailsの環境を読み込みので、アプリケーションのコードが変わった際には再起動の必要がある。
まず、Resqueはpidを保存してくれたりしないので、monitのFAQに従い、簡単な起動用のWrapperを書きそれをmonitに監視させている。Capistranoでのdeployプロセスでは、monitのrestartコマンドを呼ぶだけでResqueのworkerも再起動してくれるようになった。
ちょっとこの辺が最初だけとは言えめんどくさい。
監視に関して
ここがまだ弱いのだけど、とりあえずResqueに添付されているWebアプリケーションを目視するという弱い方法で行っている。ここは改善予定。待て次号!
とりあえず、こんなところ。