著作一覧 |
db:migrate
――これに尽きるのではないか。
というか、コードのリファクタリングは(テストのことはちょっとおいておくとしても)すさまじく低コストにできるのだが、リレーションのリファクタリングはとてつもなく高コストなはずなのに、db:migrateによってえらく低コストになっている(と実感している)。
すでにインスタンスを永続化していても、タスクをちょろっと書いてrakeを流せば済むようにフレームワークがあるので実にお気楽にできる。
これはとんでもないなぁ。
・結果的にデータモデルを多少バータリーに決めても、後で軌道修正が無茶苦茶簡単にできる。
例としてタイヤのテーブルと、自動車のテーブルとオートバイのテーブルがあり、自動車用のタイヤもオートバイ用のタイヤも同じタイヤテーブルで管理しているとする。
自動車はタイヤを持つし、オートバイもタイヤを持つ。
一方、生産年度というかロットでタイヤを管理することで、不良品のタイヤを履いている自動車やオートバイに対して通知をするような仕組みが必要とする。つまりタイヤ側からもオートバイや自動車に対してのリレーションシップが必要だとする。
ActiveRecordの楽ちんなhas_manyとbelongs_toを使いたいというのは大前提だ。
とすると、自動車 has_many タイヤであり、オートバイ has_many タイヤなのは当然としてタイヤ側にとってはbelongs_to 自動車であり belongs_to オートバイなんだが、これは嬉しくない。
なんで嬉しくないかといえば、商売を広げて飛行機が出てきた場合、飛行機 has_many タイヤとして、タイヤ belongs_to 飛行機を追加するのか? ということになる。
いくらmigrateが簡単とは言え、こんな調子でばかばかタイヤに自動車_idとかオートバイ_idとか飛行機_idとか追加するのはあり得ない設計だ。
というわけで、代替案を考えると、ActiveRecordの仕組みを使った素直な実装は、STIで共通テーブル(乗り物大集合)に対して自動車やらオートバイやらのサブセットを定義することだが、おれはイヤだ。いくら方便とは言え、実装は全部入りスーパークラスの部分集合で具象クラスを表すというのは、オブジェクト側がまともに見えても下品だと感じる。
具象の世界でいえば、タイヤテーブルになんちゃらidをどんどこ追加するのがイヤというのが最初にあるわけで、同じようにウルトラスーパーな乗り物にあらゆる乗り物の属性をぶち込むなんていうのが許容できるわけがない(具体的な作業においては必要に応じてカラムをばんばん追加してどんどこdb:migrateすれば良いだけなので作業負荷はほとんどない。つまり、そんなにまずくはない。こうなると美意識の問題としか言いようがない)。
で、IOのオーバーヘッドに目をつぶれる程度のhash_manyしかないということから、has_many throughを使って、自動車とタイヤのジョイントテーブル、オートバイとタイヤのジョイントテーブルをそれぞれ作って、タイヤは何もhasせずに、ジョイントテーブルがそれぞれに対してbelongs_toし、自動車やオートバイはそれぞれの専用ジョイントをhas_manyするようにした。本物の乗り物であればジョイントというよりはサスペンションだな。
# パフォーマンス的には最悪の選択だが(STIに比べてアクセスは倍増する)、抽象モデルと具象モデルのバランスとしては、この例の場合については、おれにはhas_many throughが最も良いと感じる。パフォーマンス重視であれば(何しろアクセス倍増だから)、STIを使うべき局面ではある。というのはわかっている。
ジェズイットを見習え |