こんちには、鈴木です。
最近、Rails3 を使用した案件があったので、その中で思ったこと、分かったことをまとめようと思います。
ちなみに Rails3 を使った案件は初めてではなかったのですが、「View はエラー画面だけ」のような特殊なものだったので、スタンダードな Rails3 案件という意味では初めてでした。
案件の特徴としては、「Rails3/Ruby1.9」「モバイル対応」「開発中に仕様が決まる/変わる」「スケジュールはタイト」という具合でした。
モバイルで文字コード絡みの問題が発生した
モバイル対応するなら jpmobile を使えば OK くらいに考えていましたが、文字コード絡みでいくつか問題が発生しました。
Ruby1.9 から文字列がエンコーディング情報を持つようになったため、文字コードを適切に扱えていないケースで EncodingError が発生してしまいました。(例外が発生しないにしても文字化けになったり・・)
具体的には、POST で送られてきたパラメータについては jpmobile が対応してくれたので良かったのですが、GET で渡されたパラメータは自分で URI エンコード/デコードする必要がありました。
モバイルについては、実機でテストする時間と、何か問題が発生した時に対応する時間をきちんと見込んでおくことが重要だな、と感じました。
仕様変更の匂いを感じたときは grep しやすい名前を付けた
「ここは仕様が変わりそうだ」と感じるようなところは、モデルやヘルパーのメソッドに切り出した上で、grep しやすい名前を付けるようにしました。
例えば、View でユーザの名前を出すところが何ヶ所もあるとします。とりあえずは「田中さん」というフォーマットで表示する事に仮決定されていますが、今後変更される可能性が高く、それが「田中」になるのか、「田中太郎」になるのか、「田中さん」になるのか、はたまた「プレミアム会員 田中様」になるのか、色々なパターンが考えられますが、まだ決まっていない・・・。そのような時は View で「<%= @user.name %>」のように書くのではなく、モデルやヘルパーのメソッドとして切り出すようにしました。以下のような formatted_user_name というメソッドを作り、それを呼び出すようにしました。
1 2 3 4 |
# TODO 表示フォーマット決定後に整理する def formatted_user_name(user) "#{user.name}さん" end |
このようにすることで、表示フォーマットが決まった段階で「formatted_user_name」の実装を変更するだけで済みますし、仮に「そこにはユーザ名ではなくユーザのランクを表示することに変更!」となっても、grep で「formatted_user_name」を使用している箇所を洗い出し、「<%= user.rank %>」に置換するだけで済みます(最初から「<%= user.name %>」のように実装していた場合、「name」のような良く使う文字列で grep することになり、関係ない部分までヒットしてしまい面倒です)。
Java の場合では変数名やメソッド名を変えたい場合は IDE の機能で安全に一括置換することができますが、Ruby のようなスクリプト言語では、まだまだ簡単にはできません。そんな時は後で一括変更することを見越して grep しやすい名前を付けておくことも一つの手かなと思います(そういうコードをそのまま放置したらダメですが)。
テストコードは重要だった
よくある話に「時間が無かったのでテストコードは書かない」というものがありますが、時間が無いからこそテストコードを書くことが重要! と強く感じました。
「時間が無い」ということは、それ以前のフェーズで実装フェーズを圧迫する何かがあったということです。
「カットオーバーの日は既に決まっている」「仕様の確定に予想以上に時間がかかってしまった」「実装開始をこれ以上遅らせることはできない」「開発はスタートして仕様は作りながら決めましょう」というものが良くあるパターンでしょうか。
そのような状況では、実装済みのコードに手を入れる頻度が高くなりますので、エンバグやデグレードのリスクが非常に高くなります。
テストコードがあれば既存のコードを安心して変更することができます。リファクタリングもやりやすいので、開発終盤になってもスピードを落とさずに駆け抜けることができました。
自動化すると楽だった
アプリケーションのデプロイや、初期データの更新、テスト用データの登録やその他もろもろ・・。
何度も行う作業を自動化したことで、だいぶ楽をすることができました。
自動化の方法は、シェルスクリプトを作成したり、rake タスクを作ったり、自動化ツールを導入したり、色々あります。
具体的にやったことは以下のとおりです。
デプロイツール Capistrano の導入
Capistrano は過去にも使ってきましたが、デプロイ作業を自動化するための力強い味方です。
初期データを登録する rake タスクの作成
初期データの登録方法は Rails の中でも比較的自由な部分であり、「rake db:seed で db/seeds.rb が実行される」ということしか決まっていません。
そこで、「rake db:seed:users」のようなテーブルごとに初期データを登録する rake タスクを作成しました。
初期データを登録する rake タスクは何度実行しても大丈夫なように、「既存データの削除 → シーケンスをリセット → データ登録」という順番で行うようにしました。
そうすることで、初期データに変更があった場合でも、「rake db:seed」を実行すれば良い(=その他の面倒な作業が必要ない)ので楽です。
ユーザが初期登録するデータのサンプルを登録するスクリプトの作成
初期データでは無いものの、ユーザが登録するデータがある場合もあります。
そのようなデータのサンプルを登録するスクリプトを作成しました。
良くある失敗談として、「開発中は「テストテスト」のような値しか入れていなかったので気付かなかったが、本番稼働してリアルなデータが登録されたら、想定よりも長い文字数が登録されたのでデザインが崩れてしまった」というものがあります。
そのような失敗を犯さないためにも、リアルなデータを簡単に登録できるスクリプトがあると便利です。
ER図からコードを生成するツール
ER図の作成には A5:SQL Mk-2 というツールを使ったのですが、作成した ER 図から Rails のモデルやマイグレーション、ロケールファイルやユニットテストなどを生成するツールを事前に作っていたので、ER図の修正をすぐにソースコードに反映することができました。ER 図を見ながら手作業でマイグレーションを作成、モデルを作成、・・・などとやる場合と比べると、開発スピードがすいぶん違います。
準備八割
システム開発では正しい開発プロセスで進めることも重要ですが、開発が始まる前に出来る限りの準備をすることも重要だと感じました。
今回は、案件が始まる前に汎用的な機能を Gem ライブラリとしてまとめていたので、「どのプロジェクトでもよくある処理」を手軽に実装することができました。
また、Gem 以外のツール(上で紹介した ER 図からコードを生成するツール)も事前に準備していたことでだいぶ楽することができました。
準備八割という言葉がありますが、まさにその通りだと思います。
まとめ
このエントリは、Rails3 案件をやってみての素直な感想を伝えられたらと思いながら書きました。
良かったことも悪かったことも含めて書きましたので、グッドノウハウばかりではありません。
こうした方が良いんじゃないか、というご意見がありましたら教えていただけたら嬉しいです。
今回書いたこと以外にも、「ああすれば良かった」「こうすれば良かった」と思うところはたくさんありますが、それはまた別の機会にご紹介させていただきます。
作成したライブラリやツールについては、可能な限り公開したいと思います。
それでは、Enjoy Rails!