Rubyによるデザインパターンを読んだ
恥ずかしながら10年以上プログラミングをやっていて、今までちゃんとデザインパターンを勉強したことがありませんでした。
それぞれのパターンはなんとなく知っているけど、ちゃんと理解できてはいないという状態でした。
デザインパターンを勉強しようとしたことは何度かありました。しかしJavaやC++で解説した書籍・Webサイトでは、いちいち本質的ではない基底クラスやインターフェイスを作っているように見えて、理解が進みませんでした。

- 作者: Russ Olsen,ラス・オルセン,小林健一,菅野裕,吉野雅人,山岸夢人,小島努
- 出版社/メーカー: ピアソン桐原
- 発売日: 2009/04/01
- メディア: 単行本
- 購入: 13人 クリック: 220回
- この商品を含むブログ (64件) を見る
この本の良いところ
この本が良いと思ったのは以下の点です。
- Rubyの動的な性質を活かしている
- パターンが厳選されており、説明の順序もわかりやすい
- 解決したい問題とそれを解決するコードがある
1. Rubyの動的な性質を活かしている
本書では、Rubyの動的な性質を活かすことで、無駄な基底クラスやインターフェイスなしにパターンを実現しています。
最初は Java に近いクラス設計をした上で、Rubyのパワーでリファクタリングしていき、簡潔なコードでデザインパターンを表現していきます。
ちなみに第2章にRuby自体の解説もあるので、Rubyに詳しくない人でも読めると思います。
2. パターンが厳選されており、説明の順序もわかりやすい
本書では、GoFの23パターンのうちの14パターン+Rubyオリジナルの3パターンを解説しています。
一度に多くのパターンを学んでも理解が追いつかなくなるので、よく使うものに絞られていて良かったです。
説明する順番も、パターン同士の結びつきが考慮されており、理解しやすいです。最初に Template Method というわかりやすいものを取り上げ、次に継承ではなく委譲で実現するために Strategy を使うといった具合です。
ABC順にAbstract Factoryから解説されると辛いです。
3. 解決したい問題とそれを解決するコードがある
それぞれのパターンについてまず問題があり、それを解決するよう設計を改善していくという流れで説明されているのでわかりやすいです。
なぜ他のやり方ではダメで、そのやり方を選んだのかがわかるので、理解が深まります。
Webサイトによっては、UMLやコードがほとんどで、背景が簡単にしか書かれていないことがありますが、そういうサイトは一度ちゃんと理解した人が見返すためのものなんだと気づきました。
さらに知るために
本書で、解説しているのはGoFの23パターンのうちの14パターン+Rubyオリジナルの3パターン(DSL、メタプログラミング、Convention over Configuration)です。
GoFのパターンのうち、解説されていないのは以下の9パターンです。
- Prototype
- Bridge
- Facade
- Flyweight
- Chain of Responsibility
- Mediator
- Memento
- State
- Visitor
これらを含めて、今後改めてGoF本を読んで勉強したいと思います。

- 作者: エリックガンマ,ラルフジョンソン,リチャードヘルム,ジョンブリシディース,Erich Gamma,Ralph Johnson,Richard Helm,John Vlissides,本位田真一,吉田和樹
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 1999/10
- メディア: 単行本
- 購入: 21人 クリック: 711回
- この商品を含むブログ (206件) を見る
まとめ
パターンによって、あるあるだなーとか、こんなやり方があるんだとか、感想はいろいろでした。ただ、全体を通して名前がついていることの重要性、そして「パターン」という言葉の意味を理解できました。
名前をつけて他人と共有できる「パターン」は、デザインパターンだけではないので今後も勉強していきたいと思います。
ここまで書いておいて非常にアレですが、本書は現時点で入手が困難です。実は、何年も前に良さげだなーと思って買った後、そのまま積んであったのです。
新品の紙の本は売ってないし、電子書籍にもなっていないのが残念です。良書なので、ぜひ電子書籍で発売してほしいです。
ちなみに原著は電子書籍でも販売されていますが、読んだことないのでなんとも言えません。Amazon.co.jpのレビューには平易で読みやすいと書かれていますが、Amazon.comにはKindle版のフォーマットが非常に読みにくいというレビューもあります。

Design Patterns in Ruby (Addison-Wesley Professional Ruby Series)
- 作者: Russ Olsen
- 出版社/メーカー: Addison-Wesley Professional
- 発売日: 2007/12/10
- メディア: ハードカバー
- クリック: 12回
- この商品を含むブログ (5件) を見る
Ruby製アプリじゃなくてもTurnipで自動受け入れテストがしたい
Python製のWebアプリケーションの自動受け入れテストをしたくて、調べてみました。
Ruby界隈だと、最近ではCucumberに代わってTurnipというツールが流行っているみたいなので試してみました。
自動受け入れテスト用のライブラリ
Rubyで自動受け入れテストをしようとすると、以下の3つの選択肢があるようです。
- Cucumber
- テストケースを自然文で書けるため、非プログラマでも読みやすい。
- Turnip
- RSpecのfeature spec
Cucumberは以前にも使ったことがあるので、今回はTurnipを選択してみました。詳しい説明は以下のページに譲ります。
- Rubyist Magazine - エンドツーエンドテストの自動化は Cucumber から Turnip へ
- Rspec/Capybara/Turnipの入門記事を全力でまとめてみた - 酒と泪とRubyとRailsと
Webページを自動操作するライブラリ
Webページの自動操作にはCapybaraを使います。デフォルトではRackTestというドライバが使われますが、これはHTTP通信を行わないドライバでありRackアプリケーションでしか使えません。
このためHTTP通信を行う他のドライバを使います。ヘッドレスでJavaScriptを利用できるドライバとして、以下の2種類があるようです。
- capybara-webkit
- Qtを利用したWebKitドライバー
- Poltergeist
- PhantomJSを利用したWebKitドライバー
最近ではPoltergeistのほうがインストールが簡単かつ高速で人気らしいので、今回はPoltergeistを使いました。
前提
前提として、Ruby 2.1*1 およびBundlerがインストールされているものとします。
PoltergeistのインストールにはPhantomJSが必要なので、 PoltergeistのREADMEに従ってインストールします。
Macならば brew install phantomjs で簡単にインストール出来ました。
準備
適当なフォルダを作ります。
$ mkdir bus-spec $ cd bus-spec
以下のコマンドでGemfileを作ります。
$ bundle init
Gemfileを以下のように編集します。
source "https://rubygems.org" gem 'turnip' gem 'capybara' gem 'poltergeist'
以下のコマンドでGemをインストールします。
$ bundle install --path=vendor/bundle
TurnipのREADMEを参考に、テストに必要なファイル・フォルダを作成します。
$ mkdir -p spec/{features,steps}
.rspecを以下の内容で作成します。
-r turnip/rspec
spec/spec_helper.rbを以下の内容で作成します。
Dir.glob('spec/steps/*steps.rb') { |f| load f, true } require 'capybara/rspec' require 'capybara/poltergeist' Capybara.default_driver = :poltergeist # 以下の関数はGeolocation APIをシミュレートするヘルパー関数です。 def simulate_location(latitude, longitude, accuracy=0) Capybara.current_session.execute_script <<-EOS window.navigator.geolocation = { getCurrentPosition: function(success) { var position = {coords: {latitude: #{latitude}, longitude: #{longitude}, accuracy: #{accuracy}}}; success(position); } }; EOS end
rspecを実行して以下のように表示されれば準備完了です。
$ bundle exec rspec No examples found. Finished in 0.00005 seconds 0 examples, 0 failures
Turnipによる受け入れテスト
それではTurnipによる自動受け入れテストを書いていきます。
spec/features/search.featureには、プログラムに詳しくない人が読んでもわかる書式(Gherkin形式)で機能を記述します。
# encoding: utf-8 # language: ja 機能:PCまたはスマートフォンでバス停を検索 シナリオ:トップページにアクセスして検索する 前提ポケドスにアクセスする 前提"京都市役所"に居る もしトップページを表示する ならば画面に"近くのバス停を探す"ボタンが表示されていること もし"近くのバス停を探す"ボタンをクリックする ならば画面に"この近くのバス停"と表示されていること かつ画面に"京都市役所前: 91m"と表示されていること
プレースホルダーに日本語を使う場合は、""で囲うなど少し工夫が必要です。参考:Ruby - Turnip で placeholder のマッチングを柔軟にする - Qiita
spec/steps/bus_steps.rbには、上で書いたGherkin形式のステップ(「前提」「もし」「ならば」など)に対応するプログラムを書きます。
# encoding: utf-8 step 'ポケドスにアクセスする' do Capybara.app_host = 'http://bus.capybala.com/' end step ':placeに居る' do |place| case place when '京都市役所' @place = {lat: 35.01129870069897, lng: 135.76807713296512} else raise "Unknown place" end end step 'トップページを表示する' do visit '/' simulate_location(@place[:lat], @place[:lng]) if @place end step '画面に:labelボタンが表示されていること' do |label| expect(page).to have_link(label) end step ':labelボタンをクリックする' do |label| click_link label end step '画面に:textと表示されていること' do |text| expect(page).to have_content(text) end
再度rspecを実行して以下のように表示されれば成功です。
$ bundle exec rspec . Finished in 2.92 seconds 1 example, 0 failures
まとめ
Turnipはこのように、テストする機能を自然文で書けるテストライブラリであり、Capybaraと組み合わせることでWebサービスの自動受け入れテストを行えます。
2012年に書いた記事と比べると、Cucumber → Turnip、capybara-mechanize/capybara-webkit → Poltergeistと変化しました。
正直Rubyをゴリゴリ書いていない身としては、TurnipのCucumberに対する利点として挙げられる、RSpecが使える点とプレースホルダーが簡単に書ける点が、それほど嬉しいことなのかよくわかりませんでした。
また、CucumberやTurnipのGherkin書式は、普通のテストを書くのに比べてコストがかかる割に、どの程度受け入れられるの?という考えもあります。 参考:RSpecで、Cucumberのような結合試験のspecを記述する - 高尾宏治日記 on はてな
うまく使えば強力なツールですが、使いドコロをよく考えて使う必要があるでしょう。
ここで説明したものをもう少し複雑にしたコードをGitHubで公開しています。
参考サイト・書籍
- Rubyist Magazine - エンドツーエンドテストの自動化は Cucumber から Turnip へ
- Turnip について (1) / まずは動かす - Thanks Driven Life
- Everyday Rails… Aaron Sumnerによる et al. [Leanpub PDF/iPad/Kindle]
*1:今回は2.1を使いましたが、1.9.3以上ぐらいで動くと思います。
かっこいいダッシュボードが簡単に作れるDashingがすごい
はじめに
まずはデモを見てくれ!デスクトップPCなどの大きい画面で見るのがおすすめです。
Windows 8風のフラットなデザインで、いろいろ動いていてかっこいいですね。こんな感じのダッシュボードを簡単に作れるライブラリがDashingです。
Ruby, HTML, SCSS, CoffeeScriptで少しコードを書くだけで簡単にカスタマイズできるので、使い方を簡単に紹介します。
プロジェクトの開始
Getting Startedに書いてあるとおり、
$ gem install dashing $ dashing new sweet_dashboard_project $ cd sweet_dashboard_project $ bundle $ dashing start
これで、http://localhost:3030/をブラウザで開けば、デモと同じダッシュボードが表示されます。
ちなみにGem環境が汚れるのが気になる場合は、以下のようにするのがおすすめです。dashing newは、templates/project をカレントディレクトリにコピーしてくるだけです。
$ wget https://github.com/Shopify/dashing/archive/master.tar.gz $ tar zxvf master.tar.gz $ mv dashing-master/templates/project sweet_dashboard_project $ cd sweet_dashboard_project $ bundle install --path=vendor/bundle $ bundle exec dashing start
プロジェクトのディレクトリ構成
プロジェクトにはいくつかのファイルとディレクトリがありますが、重要なのは以下の3つのディレクトリです。
- dashboards:ウィジェットの配置を定義するHTML (eRuby)
- jobs:Rubyで書かれたサーバーサイドのジョブ
- widgets:HTML / SCSS / CoffeeScriptで書かれた一つ一つのウィジェット
レイアウト
ウィジェットの配置はHTMLで記述します。<li>で配置やサイズを記述し、<div>でウィジェットの種類やそのパラメータを記述します。
以下は、オレンジ色のテキストを表示するウィジェットと、紫色のSynergyのメーターのウィジェットの例です。
<li data-row="1" data-col="1" data-sizex="2" data-sizey="1"> <div data-id="welcome" data-view="Text" data-title="Hello" data-text="This is your shiny new dashboard." data-moreinfo="Protip: You can drag the widgets around!"></div> </li> <li data-row="1" data-col="1" data-sizex="1" data-sizey="1"> <div data-id="synergy" data-view="Meter" data-title="Synergy" data-min="0" data-max="100"></div> </li>
ウィジェット
ウィジェットは、HTML / SCSS / CoffeeScriptで記述します。以下は、テキストを表示するウィジェットのHTMLの例です。
<h1 class="title" data-bind="title"></h1> <h3 data-bind="text | raw"></h3> <p class="more-info" data-bind="moreinfo | raw"></p> <p class="updated-at" data-bind="updatedAtMessage"></p>
データを表示するだけであれば、データ・バインディングを使って簡単にデータを表示できます。
ジョブとHTTP API
サーバーサイドのジョブを以下のようにRubyで書くことができます。SCHEDULERで定期的にジョブを実行し、send_eventでクライアント側のウィジェットに値をプッシュできます。
require 'net/http' require 'json' search_term = URI::encode('#todayilearned') SCHEDULER.every '10m', :first_in => 0 do |job| http = Net::HTTP.new('search.twitter.com') response = http.request(Net::HTTP::Get.new("/search.json?q=#{search_term}")) tweets = JSON.parse(response.body)["results"] if tweets tweets.map! do |tweet| { name: tweet['from_user'], body: tweet['text'], avatar: tweet['profile_image_url_https'] } end send_event('twitter_mentions', comments: tweets) end end
また、ダッシュボードの一番下に表示されているとおり、次のようにしてJSONをPOSTすることで、外部からダッシュボードの値を更新することもできます。
$ curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://localhost:3030/widgets/welcome
iPadをダッシュボードにする
適当なディスプレイが手元になかったので、iPad用にダッシュボードを作ってみました。時計と天気とスケジュールと特に意味のないメーターを表示させています。

実際のところ、iPadはずっとつけておくと電池が持たないし、どこかに持って行ってしまうこともあるのであまり使えてないですが。。
まとめ
Dashingによって、簡単に綺麗なダッシュボードが作れます。オリジナルのウィジェットを作る際も、面倒なところをほとんど気にせずコードを書けるので、幸せな気持ちになれます。
綺麗に表示させるためには、ディスプレイのサイズに合わせてウィジェットのサイズや文字のサイズを調整しないといけない点は、改善の余地があると思いますが。
iPad用に作ったダッシュボードの他に、勤務先でもDashingでダッシュボードを使って情報を表示させていますが、やはり綺麗に表示されているといろんな人が興味を持ってくれるのでよいです。
この記事 にあるような、大きなディスプレイが使えるといいのですが、簡単には買ってもらえません。仕方なく20インチ程度のディスプレイにダッシュボードを表示させていますが、近づかないとよく見えないので、チーム全員で共有する用途には難しいなーと思ってます。
大きなディスプレイが欲しいです。
参考:
