第2部 規約の頂点 2004-2008 — ActiveRecord の世界
この部だけは敬意から書き始める。これから語る構成は、当時の最適解だった。 手元のモノリスはこの時代の子であり(実装は Yii 1.1 だが、思想は Rails が広めた ActiveRecord そのものである)、移行は否定ではなく移住である。
言語 — 「設定より規約」の革命
Section titled “言語 — 「設定より規約」の革命”LAMP スタックが世界の Web を動かし、動的言語は黄金期を迎える。決定的だったのは2004年の Ruby on Rails である。その登場の仕方が象徴的だ。DHH の15分の動画、「Whoops!」と言いながらブログを作る。J2EE の世界で同じものを作るには、第1部の末尾で見た XML の山が要った。Rails はその山を丸ごと消した。
Convention over Configuration。クラス Post はテーブル posts に対応し、主キーは id で、外部キーは post_id だ。規約に従えば設定は書かなくてよい。J2EE が「すべての判断を宣言しろ」と言ったのに対し、Rails は「判断はフレームワークが済ませた。違うときだけ言え」と言った。これは本書のテーゼの第2行「判断を手順に変換する」の、開発者体験における最初の実演である。生産性は桁で変わった。
ActiveRecord — オブジェクトは行である
Section titled “ActiveRecord — オブジェクトは行である”この部の主役はフレームワークではなく、1つのパターンである。Fowler が『PoEAA』(2002)でカタログ化した ActiveRecord: クラスはテーブル、オブジェクトは行、属性はカラム、save で永続化、find で取得。オブジェクト自身が自分の永続化を知っている。Fowler 自身は同じ本で、このパターンは「ドメインロジックが単純なときに適する」と注意を書いている。複雑なドメインには Data Mapper(ドメインオブジェクトとテーブルの間に変換層を置く)を推した。しかし Rails が選んだのは ActiveRecord で、Rails が勝ったので、注意書きは読まれなかった。
PHP 圏は即座に追随した。CakePHP(2005)、symfony(2005、当初は Propel を同梱)、CodeIgniter(2006)、Yii(2008)。Python では Django(2005)が同じ形の ORM を持った。言語は違っても、クラスの形は同じだ。バリデーションは rules() や validates に、副作用は afterSave や after_save に、関連は relations() や has_many に。2004年から2010年頃までに作られた Web アプリケーションの大半は、この同じクラスを中心にしている。 フレームワーク名ではなく、パターン名で語るべき理由である。
規約の時代の本質は、人間が規約を守り続けることに全賭けしたことにある。テーブルを触るのはモデル経由で、バリデーションは rules() に、副作用は afterSave に。守られている限り美しく高速だった。代償は後から来る。オブジェクト=行の同一視は、3つの別々の関心を1つのクラスに同居させる。
| 関心 | 本来の主 | AR ではどこに行くか |
|---|---|---|
| ドメインの不変条件(注文は在庫を超えられない) | ドメインモデル | rules() と beforeSave |
| DB の都合(カラム名、NULL の扱い、型変換) | マッピング層 | 同じクラスの属性 |
| 表示の都合(ラベル、フォーマット) | ビューモデル | attributeLabels() とゲッター |
破線の矢印が移行の作業そのものである。1クラスに同居していた3つを、本来の主に返す。
コードベースの成長とともに、3つの関心が互いを引っ張り、モデルは神クラス化する。afterSave の中から別のモデルを save し、その afterSave がさらに別を save する。誰も全体の実行順序を知らない。規約は破っても即座には壊れない。壊れないから破られ、破られたことに気づく機構がない — これが規約の構造的限界である。
契約記述 — XML が負け、JSON が勝つ
Section titled “契約記述 — XML が負け、JSON が勝つ”この時代、契約記述の線でも革命が起きた。皮肉なことに、引き金は XMLHttpRequest だった。2005年に Jesse James Garrett が Ajax と命名した手法は、名前に XML を含みながら、実務ではほとんどの場合 XML を運ばなかった。ブラウザが JavaScript を話すなら、JavaScript のオブジェクトリテラルをそのまま送ればよい。Douglas Crockford が JSON を整理し(RFC 4627 は2006年)、パーサは eval で1行だった。
XML は契約を書けたが、書くのも読むのも重かった。SOAP のエンベロープと名前空間は、「商品を返す」だけの API には過剰だった。Fielding の博士論文(2000)が定義した REST は、この時代に「HTTP と JSON で済ませる」という実務の標語になる。契約の宣言(WSDL)は捨てられ、契約はドキュメントと、サンプルレスポンスと、相手の善意に戻った。設定も同じ道を辿る。XML の設定は YAML(2001年登場、Rails の database.yml で普及)に置き換わった。軽くなった。そして、検証できなくなった。XML Schema が持っていた「構造を宣言して機械が検証する」は、重さと一緒に捨てられた。この捨てたものを拾いに戻るのが第5部である。
1998年から2006年までの上り下りと、2015年以降の再来。間の9年間、契約はドキュメントと善意に戻っていた。
データ — MySQL と職人芸のスケール
Section titled “データ — MySQL と職人芸のスケール”MySQL が Web の標準 DB となり、スケールは職人芸で解かれた。リードレプリカへの参照逃がし(レプリケーション遅延という新しいバグを連れて)、アプリ側シャーディング(ユーザー ID の剰余で DB を選ぶ。跨ぐクエリは書けない)、memcached(2003、LiveJournal が作った)。Flickr や Facebook のスケールの講演は、この職人芸の共有である。
そして ALTER TABLE はテーブルロックの時代だった。MySQL 5.0/5.1 でカラムを足すと、テーブル全体をコピーして作り直す。その間、書き込みは待たされる。1億行のテーブルなら数時間。スキーマ変更とは深夜メンテナンスの告知であり、大きいテーブルの変更は数時間の祈りだった。ここで業界に刷り込まれた恐怖 — スキーマ変更は危険だから避ける — は、カラム名の嘘(実態と違う名前を直せない)や、使われないカラムの堆積として、今日のレガシー DB に地層のように残っている。Rails のマイグレーション(スキーマ変更をコードとしてバージョン管理する)は大きな進歩だったが、ロックの問題を解くものではなかった。
アーキテクチャ — MVC モノリスとリリーストレイン
Section titled “アーキテクチャ — MVC モノリスとリリーストレイン”MVC モノリスが標準形となる。1つのコードベース、1つの DB、1つのデプロイ。デプロイはメンテウィンドウに列車のように束ねられ(リリーストレイン)、失敗すれば全員の変更が巻き戻る。列車を逃すと次は2週間後なので、未完成の機能を「とりあえず乗せる」誘惑が働く。乗せた未完成の機能が列車を止める。
それでも、数人のチームと1台の DB に対しては、これが最速の構成だった。 トランザクションは1つの DB の中で完結し、JOIN は自由で、デプロイは1回で、ログは1箇所にある。分散の第一次授業料を知っていれば、この単純さは美徳である。問題はチームが10人を超え、デプロイ待ち行列が伸び、1つの障害が全機能を止めるようになってから顕在化する。規模が規約の守れる範囲を超えたのだ。
組織 — アジャイルは来たが、壁は残った
Section titled “組織 — アジャイルは来たが、壁は残った”アジャイル宣言(2001)はこの時代に主流化したが、それは開発チーム内の革命に留まった。イテレーションで作る速度は上がったのに、届ける速度は上がらない。変更は依然として壁の向こうの運用へ投げられ、CAB の審査を待った。2週間のスプリントで作ったものが、四半期に1度のリリースを待つ。「開発は変更で評価され、運用は安定で評価される」というインセンティブの対立が、壁を強化さえした。CI の概念は既にあった(Fowler の論文は2000/2006)が、継続的デリバリーは前夜である。
greenfield の現在形: internal-02 の「ActiveRecord の『オブジェクト=行』の同一視を持ち込まない」は、この時代の遺産整理の宣言。rules()/afterSave を本来の主へ割り振る表は、上の3行の表を逆向きに辿る地図である。神クラスの中の3つの関心を、本来の主に返す。我々の移行は「第2部から第5部への移住」である。