予習 Rails3 (2) Thor

さて、2回目の今回は Thor。北欧神話で言うと最強らしい。
http://ja.wikipedia.org/wiki/%E3%83%88%E3%83%BC%E3%83%AB

でも Rails3 で使うのはこっち。
http://github.com/wycats/thor

Ruby の Thor は平たく言えばコマンドライン操作に対して、より簡便なオプション解釈の手段を提供してくれるDSLだ。個人的には Sake に似ているなーという印象。オプション解釈と聞いて GNU の getopt とか getopt_long といったライブラリが思い浮かぶ人もいるかもしれないが、Thor ができるのはもうちょっと広範囲に及ぶ。

Thor はgemで簡単にインストールできる。

$ sudo gem install thor

渡せるオプションは以下の形式。

:boolean - is parsed as --option or --option=true
:string - is parsed as --option=VALUE
:numeric - is parsed as --option=N
:array - is parsed as --option=one two three
:hash - is parsed as --option=name:string age:integer

では実際に例を。マニュアルから引用。使い方としては Thor クラスを継承することに始まる。

class App < Thor                                                 # [1]
  map "-L" => :list                                              # [2]

  desc "install APP_NAME", "install one of the available apps"   # [3]
  method_options :force => :boolean, :alias => :string           # [4]
  def install(name)
    user_alias = options[:alias]
    if options.force?
      # do something
    end
    # other code
  end

  desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
  def list(search="")
    # list everything
  end
end

このスクリプトを app.thor として保存し、同一ディレクトリで

$ thor list

もしくは

$ thor -T

とすると

$ thor -T
app
---
/usr/local/ruby_1_9_2/bin/thor app:install APP_NAME  # install one of the available apps
/usr/local/ruby_1_9_2/bin/thor app:list [SEARCH]     # list all of the available apps, limited by SEARCH

このようにタスクと、そのデスクリプションが表示される。なお上記のソースでは install、list、force、aliasの4つのオプションを定義している。そのため、

$ thor app:install test --force --alias=useralias

もしくは

$ thor app:list search_string

といった指定が可能になる。なお、システム全体でタスクを共有したい場合

# thor install app.thor

とすることで app.thor をどのディレクトリにいても利用できるようになる。なお、タスクのインストールはリモートURLからも可能だ。一度インストールした後にタスクに変更を加えた場合は、

# thor update app.thor

などとしてシステムにインストールされたタスクのアップデートを行う。
ところで、Thor には Thor::Group というクラスがあり、定義されたメソッドすべてを一度に実行可能だ。

class Counter < Thor::Group
  desc "Prints 1, 2, 3"

  def one
    puts 1
  end

  def two
    puts 2
  end

  def three
    puts 3
  end
end

これを counter.thor として保存してある場合、

$ thor counter

としてクラス名のみをthorコマンドに渡すことで結果「1 2 3」を得られる。
あと、Thor のマニュアルの最後には簡単なジェネレーターのサンプルがあるんだけど、Rails3 のジェネレータを理解するのに役立つだろう。

class Newgem < Thor::Group
  include Thor::Actions

  # Define arguments and options
  argument :name
  class_option :test_framework, :default => :test_unit

  def self.source_root
    File.dirname(__FILE__)
  end

  def create_lib_file
    template('templates/newgem.tt', "#{name}/lib/#{name}.rb")
  end

  def create_test_file
    test = options[:test_framework] == "rspec" ? :spec : :test
    create_file "#{name}/#{test}/#{name}_#{test}.rb"
  end

  def copy_licence
    if yes?("Use MIT license?")
      # Make a copy of the MITLICENSE file at the source root
      copy_file "MITLICENSE", "#{name}/MITLICENSE"
    else
      say "Shame on you…", :red
    end
  end
end

このようにかなりよくできているモジュールなので、Rails を使う以外に簡単なコマンドラインアプリケーションやバッチ処理などでも Thor を使うことでその開発がぐっと楽になるハズ。なお、ここで紹介した以外にももっとたくさんの機能があるのでドキュメントを見てほしい。

CIツール(Continuous Integration Tool)に夢中

一昨日から始めた Ruby の trunk の継続的インテグレーションビルド、すっかり気に入ってしまった。どれもLinuxではあるものの3プラットフォームでビルドしている。
自分はもちろん Ruby のコミッタではないのだけれど、コミットするごとにビルドが走りその結果が表示されるのをみていると、もう外野ながらも応援したくなるのだ。
その模様はこちらから

今はCIツールとして Buildbot を使っているけど、他にもフリーのものとして

などがあり、それぞれ特徴がある。例えば buildbot は

  • サーバ、クライアント共にPythonで動作する。
  • リアルタイムにビルドなどのログが見ることができる。
  • 多くのプラットフォームでのビルド状況を一目で把握しやすい。
  • マスター側の設定ファイルを編集することでスレーブ上でのビルド動作を指定できる。
  • IRCやメールによる通知も可能。
  • 各種SCMをポーリングにより監視が可能。
  • サーバプロセスが比較的軽量。
  • 簡単にインストールできる。

といった項目があげられるだろう。

さて、buildbot の代表的な使用例は何と言ってもChrome
http://build.chromium.org/buildbot/waterfall/waterfall
リンク先を見てもらえばわかるけど一目で状況を把握可能だ。

資料としてはIBMのものがわかりやすくまとまっている。
http://www.ibm.com/developerworks/jp/linux/library/l-buildbot/

自分の環境ではさらにWindows上でrubycygwinとmswin32版のビルドを設定できないかと格闘中なんだけど・・・・かなりな勢いでハマっているところ。あと、コードカバレッジやメトリクス類も設定してみたいな。

ruby の trunk を buildbot で自動ビルドする

一度 ruby の trunk をインストールするとどんどん最新ソースを追っかけたくなるもの。で、多分誰かは絶対作っているだろうと思ったtrunkの自動ビルドの仕掛けがwebを探しても見つからなかった。なので作ってみよう!!と軽いノリで調査に乗り出した。
最初は capistrano か Vlad あたりのデプロイツールを使えばできるんじゃないの?と思っていたんだけど、いろいろ調査した結果、必要なのはデプロイツールじゃなくて CI ツールなのであるという発見に辿り着き、そこで buildbot を利用することにした。

でね、できたんだ。buildbot を利用した Ruby Trunk の Continuous Integration 環境が。

でも出来た後だった、世の中に rvm という、リポジトリからソースを引っ張ってきてコンパイル&インストールしてくれて、かつ複数バージョンを共存可能というちょう便利なツールが存在するのを知ったのは。個人で使うならコレで十分じゃん・・・みたいな。さらにその後もうちょっと Google で深堀りすると chkbuild という ruby コミッタの方が作った純正CIツールまでもが発掘されるという。

そう、全くもって・・・・

し・・調べが足りませんでしたッ!!!



ということでもはやネタ程度の価値しかなくなってしまったけど buildbot は健気にもその職務を疑うことなく遂行してくれているのでその有様をさらしてみる。

http://bm.badatmath.net:8010

一応 ruby の trunk に変更が Commit されるとそれに追随して build が走る(ハズ)。テストの局面では

make test
make test-all
make benchmark

を実行するように設定した。

今のところ、悲しいことに make test も通っていないみたい。たぶん環境要因。あとbuild環境を増やせるといろいろ画面が賑やかになるのだけど、まだ一つだけ。
んー、rvmやchkbuildを発見した今となってはモチベーションがあまりわかないけどせっかくなのでもうちょっと触ってみよう。

追記:make benchmark はちょっと負荷と時間がかかりすぎるので今は外してある。

予習 Rails3 (1) Arel

Rails3 では ActiveRecord の部分で Arel という関係代数モデルのモジュールが使われるということなので少しだけ予習しておく。

CREATE TABLE articles
(
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
title TEXT,
body TEXT,
author TEXT,
create_date TIMESTAMP,
update_date TIMESTAMP
);

CREATE TABLE comments
(
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
parent_id INTEGER NOT NULL,
title TEXT,
author TEXT,
mail TEXT,
url TEXT,
body TEXT,
create_date TIMESTAMP,
update_date TIMESTAMP
);

CREATE TABLE num
(
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
num INTEGER
);

というようなテーブルを作って

require 'rubygems'
require 'mysql'
require 'arel'
require 'active_record'

ActiveRecord::Base.configurations = {
    'default' => {
        :adapter => 'mysql',
        :database => 'test',
        :username => 'username',
        :password =>'password'}
    }
ActiveRecord::Base.establish_connection('default')

Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base)

atcls = Arel::Table.new(:articles)
atcls = atcls.where(atcls[:author].eq('me')).order(atcls[:id].desc).take(100).skip(4)
atcls = atcls.project(atcls[:id].as('number')).where(atcls[:id].gt('10'))
atcls = atcls.group(atcls[:author])

puts atcls.to_sql

結果はこんな感じ

SELECT     `article`.`id` AS 'number' FROM       `article` WHERE     `article`.`author` = 'me' AND `article`.`id` > 10 ORDER BY  `article`.`id` DESC LIMIT 4, 100

JOINもやってみる

cmnts = Arel::Table.new(:comment)
cmnts = cmnts.order(cmnts[:update_date].desc)
ya_atcls = Arel::Table.new(:article)
atcls_with_cmnts = cmnts.join(ya_atcls).on(ya_atcls[:id].eq(cmnts[:parent_id]))

puts atcls_with_cmnts.to_sql
SELECT     `comment`.`id`, `comment`.`parent_id`, `comment`.`title`, `comment`.`author`, `comment`.`mail`, `comment`.`url`, `comment`.`body`, `comment`.`create_date`, `comment`.`update_date`, `article`.`id`, `article`.`title`, `article`.`body`, `article`.`author`, `article`.`create_date`, `article`.`update_date` FROM       `comment` INNER JOIN `article` ON `article`.`id` = `comment`.`parent_id`

LIKE 検索は matches を使う

atcls = atcls.where(atcls[:author].matches('me%'))

INはArrayを使って

array = [1,2,3];
atcls = atcls.where(atcls[:id].in(array))

集計も可能

n = Arel::Table.new(:num)
n = n.project(n[:num].sum.as('sum'))
#n = n.project(n[:num].average.as('sum'))
#n = n.project(n[:num].maximum.as('sum'))

実を言うと Rails 開発で ActiveRecord を使うのはあまり好きではない。
もちろん小さなアプリをテンポよく作っていくのには最適なのだけど、後で負荷が高くなった時のチューニングやサーバの再構成という局面においては他の部分と結合が密なのでかなり厄介な代物になってしまう。なので負荷が高くなりそうなアプリを開発する場合はActiveRecordを使わずにデータベースとのやりとりにはRPCなどを利用してバックエンドのインターフェースを構築し、Rails 側のコントローラと接続することで疎結合を実現させ、負荷が高くなった時点でサーバを切り離し処理内容に応じて間に処理キューを溜めるサーバをさらに挟んだりといったことを行っている。
そういう仕組みが必要になることが見込める時点で Rails 案件ではないのかもしれないけど・・・。

GitHubはいかにして始まったのか

またもや 37signals ネタなのだけれども、彼らの blog で連載されている「Bootstrapped, Profitable, & Proud」というシリーズが凄まじく面白いし参考になる。
内容はそのタイトル通り初期投資にお金をかけずに(ベンチャーキャピタルを使わずに)設立し、利益を生むまでになった(収入でいうと100万ドル以上の)会社を一社づつインタビューしてそのサクセスストーリーを披露するというものだ。

で、最新版にはみんな大好き GitHub が登場。
Bootstrapped, Profitable, & Proud: GitHub
その中から「How did the business get started?」という質問に対する回答を訳してみる。チョー訳だけど。

最初 GitHub は週末プロジェクトだったんだ、git のホスティングサイトをやりたいって Tom Preston-Werner が僕に話してくれたのは 地元のプログラミング集会(日本でいうと Ruby Kaigi みたいな)の後に一緒にスポーツバーで飲んでいた時で、彼が考えていたそのホスティングサイトとは簡単にコードを共有できて git 自体を学ぶこともできるような場になりうる、そう、git のハブになりそうなものだった。僕らは git が大好きだったんだけどコードを他の人と共有するのに簡単な方法はその当時には無かったからね、そういうサイトは何よりも必要なものだった。で、Tom は僕が手伝ってくれそうだと思っていたらしい、実際そうしたけど。


それからそのサイトを小さな部分から作り上げていくのに土曜日が来るたびミーティングするってことを始めたんだ。ブランチを食べ、お互いに持ち寄ったアイデアについて語り、実際に作り上げていった。Tom はページのデザインや機能の設計、それを僕が実装。基本的なところが組みあがったらすぐに自分の仕事場でも GitHub を使い始めた。ちなみに僕の仕事場というのは PJ Hyett と一緒に作った会社だったんだけどね。実際に仕事で使うというのは GitHub を改良するのにすごく役立ったよ。PJと僕が日々使うようになってから、GitHub こそ今まで欠けていたもので GitHub こそがその隙間をうまく埋められるものだと感じるようになったんだ。


Tom が前にいた Gravatare というベンチャーで学んだのはリソース依存のサービスをフリーで提供するということは「ウリ」となる部分がそうすることによって食われてしまうということだった。その会社でいうと高ネットワーク負荷の画像ホスティングだったんだけど、GitHub の場合で言うと git のホスティング、つまりコードを保存したり転送したりというウリではない部分に対して高額のサーバ・ネットワーク費用がかかってしまうってことだ。そのコストを何とか埋め合わせる必要がある。


そのことを頭の隅で考えながら無料のパブリックベータを友達にリリースするとすぐに軌道に乗り始めた。パブリック、もしくはプライベートのリポジトリまでも無料で作れたから実際の仕事にも使う人が現れ始めた。僕と PJ もそうだったから別に不思議なことじゃない。でもね、それから間もなくプライベートリポジトリを使うのにお金をどう支払えばいいのかとメールしてくれる人達がいたんだ。


その時点で GitHub はサーバ費用を埋め合わせる以上に儲かるかもしれないことに気づいたよ、ホンモノのビジネスになるかもって。だから制限のないパブリックリポジトリは無料で提供し続けることにして、プライベートリポジトリには課金することに決めた。言い換えると僕らは課金するように言ってくれる人たちに課金しただけなんだけどね。


PJ は GitHubの共同設立者になり、僕とPJは二人で作った会社で働くのをやめ、GitHubが僕らの働く会社になった。2008年4月10日にTomとPJと僕とでサイトを公式に立ち上げて以来、そのビジネスを続けているよ。

エンジニアにとってかなり勇気づけられる記事なのでぜひリンク先で全文を読んでほしい。


ところでこのシリーズで面白いのは動画でオフィスを紹介しているものがあるってところ。
今回も GitHub の社内を歩き回る動画付き!ひろびろー!!

美人写真を撮るのに最適なカメラは?

今日、釣りとしか思えないタイトルで日本のTLを席巻していたのが
iPhone持ってるとセックスしやすい?どう?
techcrunch.jpにしては何ともお粗末な翻訳。Sexual Partner が「性的お友達」て・・・。
ま、ネタなのでそれもありかもしれないが、元記事は面白い統計データの数々を発表してくれるので有名な okcupid のブログである。
ここではiPhoneには触れない(元記事でもネタ扱い)けど、それとは別に興味深いデータが実はこの okcupid の記事に含まれているのでちょっと紹介してみよう。

ということで元記事はこちら
Don't Be Ugly By Accident!

知っている人も多いかもしれないが、okcupid はアメリカのいわゆる出会い系サイトだ。日本の出会い系よりはよっぽど健全。だから okcupid って知ってる?って聞いたら「私も使っているわよ」みたいな反応がフツーに返ってきたりもする。

で、今回の記事はそういう出会い系に登録される写真のうちどのような写真が人に魅力的に思われるのかを扱うという、まぁそれなりに真面目な記事なのだ。

調査方法も出会い系ならではで、「デートするならどっち?」という聞き方で二つの写真から片方を選んでもらうという方法で調査を行い、その結果得られた実に1,140万もの回答をもとに今回の記事が書かれている。アップロードされた写真にはたいていExifデータがついていて、それには撮影した日付やカメラの機種、絞りの数値なども記録されているのでそこから統計的なデータを導き出せるというわけだ。

この記事で一番驚いたのはカメラメーカーの比較の部分。
Panasonicマイクロフォーサーズ機種で撮影された写真がダントツで魅力的とジャッジされているのだ。キャノンやペンタ、ニコンの一眼レフを差し置いてね。(ちなみにパナの次点はライカコンデジ

どういう部分が魅力的なのかはこの調査方法ではもちろん判明しえないのだけど、でも年頃(?)の人物を撮るのならパナソニックマイクロフォーサーズ、ということらしいので家電量販店カメラコーナーのパナ一眼担当者はまさに必見の記事である。

続いてフラッシュを炊くか否かについて。
フラッシュ使用で撮った28歳の人の写真はフラッシュを使わずに撮った35歳の人の写真と同程度の魅力になってしまうとのこと。すげー。7歳の開きをフラッシュ炊かないことで埋められるのか・・・。

他にも

  • 絞りについてはもちろん開放側で撮った写真
  • 日の出、日の入りが近い時間に撮った写真

がウケがいいということが述べられている。

最後にpanasonicマイクロフォーサーズ現行機種一覧。

37signals の Jason Freid が語る『採用』とは

最近彼は inc.com に定期的に寄稿(だいたい月初めだけど8月のはまだ)しているんだけど、その記事の中から彼の考える「採用」についてまとめてみた。

元記事はこちら(もう二か月以上前だけど・・・)
Never Read Another Resume

タイトルは「履歴書なんて捨てちまえ」という感じかな。以下、内容を箇条書きで要約。

  • 実際に必要になる前に人を雇うな。
  • 仕事がないなら如何に素晴らしい才能を持つ人材がいようとも採用するな。
  • 出来る限り社員数は増やすな。
  • 仕事を知りもせずに採用しようとするな。(自分でやってからにしろ)
  • 履歴書はみんながみんな良く見えるので役立たずだ。
  • カバーレターこそ読むべき価値がある。
  • 迷ったら文章がうまい方の応募者を採用せよ。
  • 「その」仕事を勝ち取るための応募者の努力を考慮せよ。
  • How の質問をする者は避けること、対して Why の質問はいいサインだ。
  • 「試用」せよ。

37signalsで行われている採用方法ということで大企業向けでもないし、中小企業向けでもなく、黙っていても数多くの応募があるような人気のあるベンチャー向け。ただ、どんな企業でもある程度は参考になるはず。中でも「文章がうまい方の」というのは多くの人が頷けるトコだと思う。別に言い回しがうまいとかそういうのではなくて、論理構成力があってわかりやすいということ。特にこの論理構成力というのはIT業界では必須スキルなのでIT関係での採用なら小論文とプログラムの実技テストが採用試験というところは多いのではないだろうか。

個人的に気に入っているのは How を避け、Whyに好感触を持てというくだりだ。その部分を本文から引用してみよう。

During interviews, we love when potential hires ask questions. But all questions aren't equal. A red flag goes up when someone asks how. "How do I do that?" "How can I find out this or that?" You want people who ask why, not how. Why is good -- it's a sign of deep interest in a subject. It signals a healthy dose of curiosity. How is a sign that someone isn't used to figuring things out for him- or herself. How is a sign that this person is going to be a drain on others. Avoid hows.

要するにこれは洞察力・好奇心・自己解決能力のある人材を見分けるための方法ということで、ポテンシャルを測るいい材料になるということだ。
なるほどね。

ところで、37signalsのように数多くの募集の中から有能な人材を選り抜くことができるようにはまず母数を増やすPR努力が企業には必要だ。
今日見つけたのは Twitter のPR Vid。特にこれはすごいってわけではないけれど面白かったので紹介してみる。
Twitter Is Hiring, And In A Really Awesome Way

動画の元ネタはMax Fischer clubs and extracurricular activities

最初は Company of Thieves の「Oscar Wilde」の PV が元ネタかなぁと思っていたんだけど・・・
http://www.imdb.com/video/imdb/vi1862271769/

で、さらにその元ネタはウェス・アンダーソン監督の「天才マックスの冒険」という映画。
http://www.imdb.com/title/tt0128445/

さらにさらにそのネタのマックス・フィッシャーがどんな人かというと
http://en.wikipedia.org/wiki/Max_Fisher

オハイオ州立大学のフィッシャー経営大学院設立にも貢献した人でもある。
http://fisher.osu.edu/

そのほかにもすごくすごくいろんな事をしていたのが映画を見るとよくわかる。コメディだけど。

追記:techcrunchの記事、日本語訳もアップされました。
http://jp.techcrunch.com/archives/20100809twitter_rushmore_vide/