2011-07-09

ようやく Rails3 アプリを一つリリースした。

リリースしたものよりもそこに至る過程や理由が自分にとって大事なのでそれを残しておこうと思う。

※ なんかこれしか書いてないとリリースしたものがどうでもいいように聞こえるけど、そんなことないよ! 付き合い続ける気があるからこその Rails だもの。

Rails の採用に関して

オレフレームワークとの決別と人材採用のコストダウン

これまで、PHP 4.2 以降で使えるオレライブラリ、オレフレームワークで小規模なものを作ったり、PHP 3 時代からのレガシーというか遺跡級のシステムの漸進的リプレイスなどを行っていたが、どうも限界を感じていた。なんか仕事が後ろ向きな感じもしていた。このままだとずっと時代に追いつけずに終わりそうという危機感もあった。

また、Google App Engine の登場以降感じていた「うちに必要な技術はこれだよ」と具体的にはっきり言えること、それによって生み出すことのできる人材の流動性を取り入れたいと思っていた。正直「PHP と MySQL が使えること」なんて何の指標にもならない。だからやるならメジャーで、かつまだ自分で勉強する気のある人を見分けられるフレームワークが良いと思っていた。幸い日本ではまだ Ruby や Rails はそれほど定着し切っていない。東京はともかく田舎では Ruby を書ける人は多くない。それでいて情報量は多い。もちろん英語。それがまたよい。

また適度に「枯れない」具合が Web サービスの構築にも向いている。この世界は様々なレイヤーで常識が簡単に変わる。枯れすぎていてはいけない。

そしてこの枯れない技術にキャッチアップしている人を採れば少なくとも外れはないだろうし、逆にそういう技術を採用している会社だとアピールすれば、優れた技術者にそっぽを向かれないだろう。お互いにデメリットはないはずだ。「適切なバージョン管理システムを用い、Railsなどのフレームワーク1でテスト駆動開発ができる人」が欲しいし、ユーザー企業としてはこれを実現してくれる会社に仕事をお願いしたい。

もう一つ、自分のウリにもなる。

Rails 3 がよさげだった

それまでの自分と Rails の関係はと言えば、Rails 1 の頃はついていけず、2 の頃は設計の無理矢理感や Rail からの外れにくさなどのネガティブな話をよく聞くようになったので「待っていた」。

ただ、Rails 1 で登場した ActiveRecord の migration は本当に欲しいと思っていた。DB もコードと同期が取れる。テキストで管理して漸進的に開発を進められる。まだアジャイルなプラクティスが身にしみていなかった頃でさえこの言葉は自分に突き刺さった。今も刺さったままだ。だから Rails のコピーのくせにテストのサポートもなければ migration もない CakePHP には心底頭にきた2し、いつか必ず Rails が仕事の助けになると確信していた。

Rails 3 は本当によさそうだった。

  1. Merb と統合してフレームワーク自体が疎結合になる
  2. 全面的に rack ベースになる

特に 1 についてはオレフレームワークでも密結合のダメさを痛感していた。それもあって Rails 1, 2 の頃はやはり躊躇した。

rack も注目していた技術なのでとても嬉しかった。plugin の実装が Rails 独自のものでなくなるのでライブラリがさらに充実するだろうし、特にこれで完璧に開発環境と production 環境の切り替えがスムーズになったと思った。

実際には bundler のスゴさをのちに思い知ることになるんだけど。

タイミングが良かった

Rails 3 の採用は少し賭けだったが、

  • サービスの形が見出せずに打ち合わせの期間がだいぶ長引いた
  • そうこうしているうちに Rails 3 が正式にリリースされた
  • 当初は適当なブログエンジンや CMS をカスタマイズする気でいたのだが、本心ではそういう仕事のやり方を望んでいた訳ではなかったので、一気に方針を切り替えた

正直、話が順調に進んで Rails 3 が beta の頃に Go が出ていたら採用はしていなかったと思う。それくらい自分は stable 志向だ。それに Rails の経験もなかったし。

もう一つは Ruby Enterprise Edition が 1.8.7 になっていたこと、さらに古い 1.8.5 で動いていたシステムを停止するタイミングが重なったことも大きい。テストの工数をばっさり削れた。

はっきり言って幸運だったとは思うが、REE も rvm も 1.8.5 ベースのシステムのチェックも怠らなかった積み重ねだとも思っている。

cf.

Ruby のオープンクラスと github とコミュニティを信じていた

PHP と Ruby を最もよく書いたのでこの二つの比較になってしまうが、やはり自分の中で Ruby の最後の良さは

オープンクラスであり、好きなようにモンキーパッチを書けること

だと思う。

これと、自分の中にあった Ruby に対する小さな自信が

ライブラリにバグがあった場合 PHP だと逃げようがなくても、Ruby ならなんとかなるし、大丈夫

という形で Rails 3 の採用を後押ししたし、様々なライブラリを試し、コードを書き始めてからも安心に繋がっていた。

実はこれまで何度か PHP のライブラリでは痛い目に遭っている。

  1. class の名前被りは fatal error で強制終了のクセにちゃんと pear パッケージ化して名前空間の譲り合いをしない
  2. リポジトリが svn ( or cvs )
    • 作者が放置しててパッチ取り込んでくれない

これが Ruby なら

  1. フツー gem だし名前の衝突で訳の分からないことにはならない
  2. リポジトリはフツー github なので最悪作者が放置してても fork して直せばいい
    • 自分でやらなくてもだいたい他の人がそれをすでにやってくれている
  3. 最後はモンキーパッチで逃げられる

これだけ有利な条件が揃っていて Ruby を使わないなんてどうかしてる。

結局今回はモンキーパッチで逃げ続けたものはない。最終的にはライブラリの方に吸収されて自分のパッチは捨てることができた。コミュニティが生きている感じがとても嬉しかった。

cf.

新しく取り組んだこと

基本はイテレーティブに

スクラム的にデモを重視し、定期的にデモとミーティングを重ねた。イテレーティブに進めること自体は今までも勝手に取り組んでおり、この期間でこれくらい、という見当は小さいものならついていたが、今回は今までの経験よりだいぶ大きなものになったので、イテレーティブな取り組みそのものにプロダクトオーナー(と、勝手に想定)を巻き込んでデモをするところまで行った。

結果、前半は見た目(デザイン)が追いついてこないので付き合わされる側は退屈だったようだ。

しかし自分にとっては「きついがとても良いリズム」ができたと思う。デモを木曜日に設定したのも良かった。

RSpec で TDD

テストの支援をまともにしてくれるフレームワークなんだからやらない方が嘘。本格的に使うのは初めてだが3レポートの読みやすい RSpec を採用した。中身(バックエンド)は一人でやるので時間さえ都合がつけばなんとかなるはずだった。一部 Rails + RSpec の考え方を自分が飲み込めなかったり、単にテストしにくい部分(条件に応じて変わるメールの文面とか)もあったが、まずまずの状態にはなったように思う。

ただし jQuery を使った DOM をいじる処理にテストは書かなかった。Jasmine を使って TDD を回すことはできたはずだが、初めてのことが多くなりすぎるとしんどいので JavaScript については手を抜いた。

ちなみにリンクを張るために漁っていたのだけど、自分が RSpec で BDD だぜひゃっはーと最初に感極まったのは2008年2月の RubySapporo だったことを思い出した。やる気のない土曜出勤の中「あーこれからはこれだな」と確信したのを覚えている。

ただ、このとき感じた「Ustすげぇ」は今は薄れている。このときは Ust で伝わったことの中にほとんどすべての価値があったが、今は Ust で伝わらないことの中に価値を見出そうとしている。

cf.

Fabrication でテストデータ生成

デモを重ねてプロダクトコードが変わるたびにテストデータを作り直すだろうことは最初から分かっていたので、テストデータ生成ツールにまず取り込んだ。

厳密には今回初めて取り組んだことではないが、作ったデータを seed で取り込める形に出力するなどの細かい機能改善をくり返した。

また、標準の Rails では意外に seed や fixture の扱いが良くないということがだんだん分かってきた。

cf.

RR で stub out

RSpec に RR を組み合わせてテストしにくい部分の stub out を行った。

今回改めて考えさせられたのは

今自分は何をテストしているのか

を考え続けることの大切さだった。何をテストしているのかが分かっていないと何を stub out してよいかが分からない。stub や mock という言葉だけ知っていてもこうしたツールはまったく使いこなせない。使い方が分かることと使えることの違いがものすごく大きなツールの一つだなと痛感した。

cf.

Capistrano で deploy

Capistrano の記事を最初に書いて2年半経っているが、ようやくこれを実現できた。これで手作業の転送で意図したファイルを転送し忘れたとか、余計なファイルを上げてしまったとかそういう事故は起きなくなった。TDD の安心感も絶大だが、deploy ツールの安心感もすごい。

checkout 元になる repository が svn で、これが LAN 内にあるので production 環境にどうやって持っていこうかと思ったが、svnsync を使って production 環境のあるサーバに持っていくことにした。

たぶん svnsync を試そうと思ったのはこのことが頭にあったからなんだと思う。確かそう。

cf.

管理画面のTypusのviewに手を加えないためにJSを使った

管理画面は全面的に Typus を採用した。初期の頃はやりたいこともシンプルだったので CSS の調整だけで済むかと思ったが、徐々に扱いにくさを感じてきた。しかし View に手を出し始めると、アップデートの際に構造が変わってたらやっかい。そこで

Url Dispacther を応用して特定のモデルに対する編集作業のときの画面の DOM を JS でいじる

ことにした。

これが見事にハマった。いい意味で。例えば google map のプレビュー機能とかそういう機能が欲しくなるんだけど、直接 View をいじらずに JS だけで後からその機能を追加することができるのはとても助かる。

これを知った当初はこんな風に使えるとは思ってなかったけど、JS だけでゴリゴリいけるのは JS の分かる人間だけで作っていく際にはとても便利だなと感じた。

cf.

git を基本にした

中央のリポジトリは svn なのだが、それの置き換えはともかく、今回は自身の git 経験をさらに伸ばす良い機会と捉えた。これまでは git + svn 両刀で git は master branch だけを使い、ある程度成果が出た段階で手作業で svn にも反映するという方法だった。

しかし今回は svn 上のコードのないゼロからのスタートなので最初から git で管理し、小さなストーリーくらいの単位で git の branch を切って作業した。

また当初は git-svn は使わなかった。というのも開発初期から中期に掛けては migration やコードの書き直しが多くなりすぎるし、これら全部を後から参照する必要はなかったので、ある程度の区切りがつくまで git だけで管理し、最終的には履歴を捨てて svn に突っ込んだ。

git-svn で svn と同期を始めてからは rebase や cherry-pick にも積極的に取り組んだ。svn にはできるだけきれいな commit log を残しつつ git 上には頻繁に commit をして後からどうにかなるようにしておくことを心がけた。

ハマったこと

seed とか fixture とか支援なさすぎ

意外なことに seed データや fixture について Rails はかなりあっさりしていた。seed データの生成支援も読み込み支援もなかった。読み込み用のツールを書いた。fixture の書き方の注意点も rails guide や普通の参考書籍では分からなかった。全部自分でハマってメモを書いた。

Typus がビミョー

Rails 3 になって 2 時代の管理画面用のライブラリが軒並み使えなくなった。Typus を採用したが、Typus の仕様なのか自分で Rails を使ったモデリングを分かっていないせいなのか分からない、不具合というか期待と違う動作に苦しんだ。

基本的にはよくできてると思うんだけど、いかんせん Typus については情報不足でやられた感が強い。今となってはボクは日本人としてはだいぶ Typus のクセをつかめてる方だと思う。

でも Rails 3.1 時代の標準にはならないんだよね? これ。たぶん。

新しく始めなかったこと

  • ユニットテストの自動化は 5 年以上前から行っている。ただ、これを支援してくれるフレームワークと組み合わせてやったのは初めて。
  • TDD はここ 1, 2 年くらいそこそこ真面目にやっている。
  • Selenium IDE による自動テストはいつ始めたか覚えてない。Selenium Core を使ってブラウザ依存を排除するようになったのは 1 年前だけど今回はあまり一生懸命 Selenium は使っていない。RSpec を中心にした。
  • git は 3 年くらい前から使っている。bundle ファイルはよくバックアップ代わりに使っていたが、branch や rebase, cherry-pick, stash などは使っていなかった。
  • svn によるバージョン管理は 6 年くらい行っている。と思う。(その前はCVS)
  • Trac での課題管理は 5 年以上行っている。使い方は徐々に変わってきているけど、今回もイテレーションを Trac の milestone に当てはめて作業を設計している。ただしきっちり timebox を守ったイテレーションにはできていない。短い期間や長い期間ができている。
  • Ruby は何年使ってるか覚えていない。Web アプリは古式ゆかしい CGI を除けば初めて書いた。

テストや deploy を手作業で行う弊害はずっと感じていたので、その辺の取り組みは今に始まったことではないし、そこそこ準備できていたと思う。

できなかったこと

  • Continuous Integration
  • Cucumber
  • Selenium の安定した(いちいち変更しない)テスト
  • デザイナとのクリエイティブな共同作業

まとめ

みたいなものはないよ。

あえて書くとすると、しんどかったけど、いろいろ好条件にも恵まれたなと思う。契約の絡むややこしい相手に対して 1 〜 2 週間に 1 回デモをやるというのは日本の、というか少なくともこの辺の田舎のビジネスではちょっと厳しいような気がする。社内だけで済むからこそできただろうことももちろんある。仕様を大真面目に議論してお互いの納得を作ったり、仕様の変更、追加を理由に期間を延ばしたり。そのために最初に締め切りだけを切るのはやめよう、という提案も通した。これくらいからこれくらいの期間に終わる、という予想を出し続けた。

またしんどいって言っても謎のバグが取れないとかそういうしんどさではなく、単なる作業時間の読みのずれ4だったので、「頑張ればなんとかなる」レベル。

プロジェクト自体の参加者は複数人いたが設計も実装も一人で行えたことも実は大きい。自分以外の人を教育する必要がないから。ただ、仕様をレビューしてくれる人もいないので大きな不安は残った。まぁだからこその変更に強い仕組みでもあるんだけど、このままの体制はダメだなと改めて思った。

ただ、少し自信がついた。ボクは20世紀プログラマを卒業できたかな。

  1. 上の意図が実現できれば、この点に関しては別に Rails でなくたってよい。あえて言うと Rails は考え方のハードルはあっても環境構築や実装作業そのものについてはそれほど難しいものはないと思うし、「作法に従いやすい」ツールだと思う(ポリシーがはっきりしている)ので、そういう意味でオススメするけど。 

  2. 後発がオリジナルより遅れててどうする。もちろん当時のバージョンの話で、今は調べてないので分からないけど。 

  3. TDDBCで経験自体はある 

  4. 作業があとから膨らんだケースはそんなになかったし、あったとしても予想よりすぐに対応できた。これが本当にレガシーなものだと膨らんだ先のボリュームが全然読めなかったり、2次被害3次被害が発生したりするもんだけど。 

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm