2010-04-14(Wed) [長年日記]
■1 RubyKaigi2010に関連していま思っていること
……は、Web日記に書くんじゃなくて古式ゆかしくメーリングリストというころに投稿してました。日本Rubyの会MLというメーリングリストがあるのです。
■2 Pivotal TrackerのGetting Startedの翻訳
Web日記じゃないところに書いたものつながりでお知らせ。
必要に迫られて以下をリリースしました:
私たちの役にたったので、他の誰かのお役にも立つといいなと思ってます。Happy Estimating & Planning!
アジャイルな見積りと計画づくり ~価値あるソフトウェアを育てる概念と技法~
毎日コミュニケーションズ
¥ 3,360
そういえば、『アジャイルな見積りと計画づくり』は4刷が決定したそうです。読んでいただいて、周りに口コミで紹介してくださっている皆さまのおかげです。ありがとうございます。
■3 2年前の動画をいま見てくれた人がいたということとRSpecのMacroについて
2008年の2月の雪がしこたま降っていた札幌で話をしたときの動画を、最近観てくれたことをはてなに書いてくれた方がいて、さらにご自分でいまどきのRSpecの使い方をふまえてリファクタリングしてくれていた。ありがたいことです。Ruby札幌++
そういう意味では、先日id:hyoshiokに呼び出されてお話しした動画とか、「解読」とか言うわりにはたどたどしい限りで、youtubeの分割ファイルのサムネ全部貼ってあるとか晒し者にもされるにしても程があるだろうとも思うんだけど、「未来のいつか」誰かに届くことがあるかもしれないと思う今日この頃。
話を戻して。で、上記のsubjectやnested contextを使ったリファクタリングの書き方で私がいま何かお返しできることがあるかなあ、とぼんやり考えていたところ、たまたまミーティングとミーティングの合間のビミョウな時間ができたのでちょっとやってみた。こういう書き方もできますね。
describe Game, "#score" do include BowlongGameMacro context "すべてガターの場合" do play_game { 20.times { roll_gutter } } score { should == 0 } end ... context "スペアの場合" do play_game do roll_spare roll_on_frame(4, 3) 16.times { roll_gutter } # (10 + 4) + 4 + 3 => 21 end describe "スペアの次の投球で倒したピンがボーナス加算される" do score { should == 21 } end end
これはRSpec界隈ではMacroと呼ばれている手法(たとえば、RailsCastの157: RSpec Matchers and Macros)を、こじらせた感じ。全文はこんな感じ:
$:.unshift(File.dirname(__FILE__)) | |
require 'spec_helper' | |
module BowlongGameMacro | |
class BowlongGamePlayer | |
def initialize | |
@game = Game.new | |
end | |
def roll_spare | |
@game.roll(5) | |
@game.roll(5) | |
end | |
def roll_strike | |
@game.roll(10) | |
end | |
def roll_gutter | |
@game.roll(0) | |
end | |
def roll_on_frame(*pins) | |
pins.each do |pin| | |
@game.roll(pin) | |
end | |
end | |
alias :roll :roll_on_frame | |
def score | |
@game.score | |
end | |
end | |
def self.included(base) | |
base.extend(ClassMethods) | |
base.instance_eval do | |
alias :score :it | |
end | |
end | |
module ClassMethods | |
def play_game(desc = nil, &block) | |
before do | |
@__player = BowlongGamePlayer.new | |
@__player.instance_eval(&block) | |
end | |
subject { @__player.score } | |
end | |
end | |
end | |
describe Game, "#score" do | |
include BowlongGameMacro | |
context "すべてガターの場合" do | |
play_game { 20.times { roll_gutter } } | |
score { should == 0 } | |
end | |
context "すべて1ピンの場合" do | |
play_game { 20.times { roll_on_frame(1) } } | |
score { should == 20 } | |
end | |
context "スペアの場合" do | |
play_game do | |
roll_spare | |
roll_on_frame(4, 3) | |
16.times { roll_gutter } | |
# (10 + 4) + 4 + 3 => 21 | |
end | |
describe "スペアの次の投球で倒したピンがボーナス加算される" do | |
score { should == 21 } | |
end | |
end | |
context "ストライクの場合" do | |
play_game do | |
roll_strike | |
roll_on_frame(4, 3) | |
16.times { roll_gutter } | |
# 10 + (4 + 3) + 4 + 3 => 24 | |
end | |
describe "次のフレームの得点がボーナス加算される" do | |
score { should == 24 } | |
end | |
end | |
context "ストライク、ガター、スペアの場合" do | |
play_game do | |
roll_strike | |
roll_on_frame(0, 10) | |
roll_on_frame(7, 2) | |
(7 * 2).times { roll_gutter } | |
# 10 + (0 + 10) + 10 + (7) + 7 + 2 => 46 | |
end | |
describe "ストライク後のフレームが加算されて、かつスペアの加算も成立する" do | |
score { should == 46 } | |
end | |
end | |
context "紆余曲折あったゲームの場合" do | |
play_game do | |
[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each do |pin| | |
roll(pin) | |
end | |
end | |
describe "Bob Martinの受け入れケースのスコア通りになる" do | |
score { should == 133 } | |
end | |
end | |
end |
さいしょに"Rspec Macro"って聞いたときには「えっ。何それ」って思ったんだけど、説明をみるとModule#includedとObject#extendを使ってるだけでした。
えっと、いまの時点でこれについて議論できるだけの準備が私にはありません。これは素晴しいものだよ諸君今日からみんなこう書くべきだよとか自分でも思ってません。トレードオフだよ、みたいなのもあんまり興味ないです。まずは「単なる成功したプロジェクトと失敗したプロジェクトのお話のリスト」を集めるのが先だなあと思ってます。
いまの時点での自分じしんにとっての収穫は『Growing Object-Oriented Software, guided by Tests』の"Chapter 21: Test Readability"のトピックとのつながりが見えはじめたことーー見えはじめた、というだけでそのの続きはまだ無いんだけど。
『Growing Object-Oriented Software, guided by Tests』は冒頭で紹介してある楽天さんでの講演でも少し言及したけどほんと良い本で、このタイトルだけでライトニングトークやれると思ってる。
どれぐらい良い本かというと、もしも何でも可能な世界で、私がid:t-wadaと一緒に一冊だけ技術書を書いていいと言われて、それを達成できたら(これは可能世界の話ですからね!)、できあがるのはこの本だと思う。そのときのサンプルコードはRubyだね。Steve Freeman とNat Pryceは「よく勉強している」ので、全編とおして私好みのキラーフレーズ満載。"Expect Unexpected Change"、「テストコードにはwhatを、プロダクトコードにはHowを(要旨)」、"Test-driven development combines testing, specification, and design into one holistic activity"。この本を読むことを通じて「TDDとTiDDの違いについて自分なりに整理がついた」のでした。おすすめ。