コンテンツにスキップ

第1部 規約の時代への道(1970年代-1990年代)

三つの創世の直後、業界はその実装に30年かける。この部の主役は商業化と分業である。思想は道具になり、道具は職能になり、職能は壁になった。そしてこの部の後半で、業界は初めて「ネットワークを跨いでシステムを分ける」ことを本気で試し、高い授業料を払う。

言語 — 構造化からオブジェクトへ

Section titled “言語 — 構造化からオブジェクトへ”

構造化プログラミングが常識になると、次の戦場は「変更に強い単位」の設計に移る。Constantine と Yourdon が『Structured Design』(1979)で結合と凝集の語彙を整備した。結合はモジュール間の依存の強さ、凝集はモジュール内の要素がどれだけ同じ目的に属するか。結合を下げて凝集を上げろ。この2語は今日もそのまま使われているが、当時は定義だけで、測る道具も強制する道具もなかった。レビューで人が守る規約だった。

Smalltalk(1980年の Smalltalk-80 で公開)が対話的オブジェクトの夢を見せ、C++(1985年に商用リリース)がそれを性能とともに商業化し、Java(1995)が GC と VM で「メモリ管理という職人技」を言語側へ吸収した。注目すべきは Java の成功の構図である。C++ の世界では free を忘れればリークし、2回呼べばクラッシュした。ベテランはそれをやらない。新人はやる。Java は「やらないように気をつける」を「やれない」に変えた。人間が毎回守っていた規律を、処理系という構造に変換した — 本書のテーゼの最初の大規模な実演である。

OOP は「変更に強い」を約束したが、新しい傷も残した。継承の濫用(コードの再利用のために is-a でないものを継承する)、神クラス(何でも知っている1クラス)、そして深い継承ツリーのどこを変えると何が壊れるか分からない脆弱な基底クラス問題。GoF の『Design Patterns』(1994)が「継承より委譲」を説いたのは、すでに傷が十分に深かったからだ。

データ — 関係モデルの帝国と DBA の誕生

Section titled “データ — 関係モデルの帝国と DBA の誕生”

Codd の理論は1979年の Oracle V2 を皮切りに商業化され、IBM の DB2(1983)が続き、SQL は1986年に ANSI 標準となった。Jim Gray らがトランザクションを理論化し、Härder と Reuter が1983年に ACID という語を与えた。原子性・一貫性・独立性・永続性。これは「途中で落ちたらデータが壊れる」という傷を、エンジンの保証に変えたものだ。アプリケーションは「半分だけ書かれた状態」を考えなくてよくなった。

正規化・制約・トランザクションという「データ側の構造」が揃い、RDBMS は以後30年、事実上の唯一解になる。同時にDBAという職能が生まれた。スキーマ変更は申請と審査の対象になり、インデックスの設計とクエリのチューニングは専門家の仕事になった。ロジックがストアドプロシージャへ吸われ、アプリと DB の境界が曖昧になる時代でもある。ビジネスルールが PL/SQL に書かれ、バージョン管理されず、テストもなく、DBA だけが読める。構造は手に入ったが、その番人は人間の職能だった。

アーキテクチャ — 3層と、分散の第一次授業料

Section titled “アーキテクチャ — 3層と、分散の第一次授業料”

メインフレームからクライアント/サーバーへ、そして3層(プレゼンテーション/ロジック/データ)へ。層の分離は今日の3リスナー分離にまで続く健全な遺産だ。しかし1990年代の業界はさらに野心的な夢を見た。分散オブジェクトである。CORBA(OMG、1991)、DCOM(Microsoft、1996)、EJB(Sun、1998)。ネットワークの向こうのオブジェクトを、手元のオブジェクトと同じように呼べる。メソッド呼び出しの向こうが同じプロセスか地球の裏側かを、プログラマが意識しなくてよい。位置透過性という理想だ。

結果は惨憺たるものだった。幸い、なぜ失敗するかは失敗する前に書かれていた。Sun の Peter Deutsch らがまとめた分散コンピューティングの8つの誤謬(1994年頃)である。

  1. ネットワークは信頼できる
  2. レイテンシはゼロである
  3. 帯域は無限である
  4. ネットワークは安全である
  5. トポロジは変わらない
  6. 管理者は1人である
  7. 転送コストはゼロである
  8. ネットワークは均質である

位置透過性とは、この8つを信じることに他ならない。ローカルの呼び出しはナノ秒で返り、必ず返る。リモートの呼び出しはミリ秒かかり、返らないことがあり、返らなかったときに向こうで実行されたかどうかが分からない。この非対称を隠すと、プログラマはループの中でリモートの getter を呼び、100件の一覧に100回のラウンドトリップを払う。Martin Fowler は『Patterns of Enterprise Application Architecture』(2002)でこう書き残した: 分散オブジェクト設計の第一法則 — オブジェクトを分散させるな。 ネットワークは隠蔽できない。分けるなら、境界を跨ぐ呼び出しは粒度の粗い、明示的なものにしろ。

アーキテクチャ — SOA という思想と、ESB という実装

Section titled “アーキテクチャ — SOA という思想と、ESB という実装”

分散オブジェクトの失敗を踏まえて、1990年代末から2000年代にかけて登場したのが**サービス指向アーキテクチャ(SOA)**である。Gartner が1996年に語を使い、実務の語彙になったのは2003年前後。SOA の思想は、分散オブジェクトへの反省として読むと正しく見える。オブジェクト(細かく、状態を持ち、メソッドを連呼する)ではなく、サービス(粗く、状態を持たず、1往復で仕事を終える)を分散の単位にする。

Microsoft の Don Box が2004年にまとめたSOA の4テネットは、今読んでも古びていない。

  1. 境界は明示的である — サービスを跨ぐ呼び出しは高くつく。それを隠さず、跨ぐときは跨ぐと分かるように書く
  2. サービスは自律的である — 別々にデプロイされ、別々にバージョンが上がり、相手が落ちていても自分は動く
  3. 共有するのはスキーマと契約であって、クラスではない — 実装の型を共有すると、相手の内部に結合する
  4. 互換性はポリシーで決まる — どのバージョンと話せるか、どの認証が要るかは、コードではなく宣言で表す

この4つは、Parnas の情報隠蔽をネットワーク境界に適用したものだ。テネット3は特に重要で、後のマイクロサービスが「共有ライブラリを避けろ」と言うのと同じことを言っている。同じ頃、Amazon では Jeff Bezos が2002年に全チームへの指令(後に API mandate と呼ばれる)を出したとされる。全チームはデータと機能をサービスインターフェース経由でしか公開しない。直接の DB アクセスも、共有メモリも、バックドアも禁止。インターフェースは外部公開可能なものとして設計する。後の AWS は、この指令の副産物である。SOA の思想は、思想としては正しかった。

問題は実装だった。SOA は WS-* という仕様群(SOAP、WSDL、UDDI、WS-Security、WS-ReliableMessaging、WS-Transaction…)と、**エンタープライズサービスバス(ESB)**という製品に結びついて売られた。ESB は「賢いパイプ」である。ルーティング、変換、オーケストレーション(BPEL)をバスの中に集める。サービスは賢くなくてよい。接続すればバスが面倒を見る。結果、ESB は全サービスの変更が通過する単一の場所になり、ESB チームが全社のボトルネックになった。サービスは自律的であるはずだったのに、バスの設定変更の順番待ちになった。テネット2を、製品が破ったのだ。2009年の SOA マニフェストは「ビジネス価値 > 技術戦略、進化的改良 > 完璧な追求」と書いたが、その頃には SOA の語自体がベンダーの匠と同義になっていた。分散は高くつく — 第一次授業料である。そして思想が正しくても、実装が別の場所に賢さを集めれば、思想は負ける。

設計記述 — UML と、モデル駆動の夢

Section titled “設計記述 — UML と、モデル駆動の夢”

OOP が広まると、設計を描く記法が乱立した。Booch 法、Rumbaugh の OMT、Jacobson の OOSE。1990年代前半には50を超える手法があったと言われる。3人が Rational に集まり(「三人の amigos」)、記法を統一したのが UML である。1997年に OMG が UML 1.1 を採択し、クラス図・シーケンス図・ユースケース図は業界の共通語になった。記法の統一自体は成功で、シーケンス図は今日も分散システムの呼び出し順序を説明する最良の道具である。

問題は、記法が手法を連れてきたことだ。RUP(Rational Unified Process、1998)は UML を中心に据えた重量級の開発プロセスで、実装の前に大量の図を描くことを求めた。さらに OMG は2001年に MDA(Model Driven Architecture) を掲げる。プラットフォーム非依存のモデル(PIM)を UML で描き、そこからプラットフォーム依存のモデル(PSM)とコードを生成する。プログラミングはモデリングに置き換わる、という夢である。CASE ツール(Rational Rose など)がこれを売った。

夢は叶わなかった。理由は、本書のテーゼで説明できる。モデルとコードの一致は、人間が両方を更新し続けるという規約に依存していた。締切の夜にコードだけが直され、図は古くなる。古くなった図は読まれなくなり、読まれない図は更新されない。生成の向きも問題だった。図からコードを生成すると、生成されたコードに手を入れた瞬間に往復が壊れる。「図が真実である」という前提は、真実がコードと DB にしかない現場では成立しない。

アジャイルの反動はここへ向かった。Fowler は『UML Distilled』で UML の使い方を3つに分けた。スケッチ(ホワイトボードで会話のために描き、捨てる)、設計図(実装の仕様として描く)、プログラミング言語(MDA)。生き残ったのはスケッチだけだ。2000年代後半には UML は「描いても誰も見ない図」の代名詞になり、設計の記述はコードと、軽量の文書(後の ADR、2011)と、誰でも描ける箱と線(後の C4 モデル、2018)に帰っていく。

ただし MDA の問い自体は正しかった。「定義から生成すれば、定義と実装はズレようがない」。この問いは第5部で、向きを逆にして叶う。UML という人間向けの図からではなく、SQL や OpenAPI というすでに実行されている定義から生成する。真実であるものを起点にすれば、往復は要らない。

SOA の実装を支えたのは XML である。XML 1.0 は1998年に W3C 勧告となった。SGML の簡略版として設計され、マシンにも人間にも読め、名前空間で語彙を混ぜられ、DTD と後の XML Schema(2001)で構造を宣言して検証できる。この最後の点が本質だ。XML はデータ形式である以上に、契約を機械可読に書く最初の業界標準だった。SOAP(1999)がメッセージの封筒を、WSDL(2001)がサービスの契約を、XSLT(1999)が変換を、それぞれ XML で書いた。契約があればクライアントを生成できる。WSDL から Java クラスを生成する wsimport は、今日の OpenAPI Generator の直接の祖先である。

そして XML は設定をも飲み込んだ。J2EE のデプロイ記述子(web.xml、ejb-jar.xml)、Struts の struts-config.xml、初期 Spring の Bean 定義、Ant の build.xml、Maven の pom.xml。あらゆる判断をコードの外に出し、宣言で書く。理屈は正しかったが、量が正しくなかった。クラスを1つ足すのに XML を3ファイル直す。タイポは実行時にしか分からない。この疲れが、次の部の革命の直接の動機になる。

ウォーターフォールが標準化された。皮肉なことに、しばしば出典とされる Royce の論文(1970)は、一方通行の工程を「リスクが高く失敗を招く」と批判するために図を描いたのだが、図だけが独り歩きした。米国防総省の規格 DOD-STD-2167(1985)がこれを調達の条件にし、業界全体の既定値になった。

1989年の ITIL が運用管理を体系化した。その中核が**変更諮問委員会(CAB)**である。変更はリスクであり、リスクは会議と申請書で統制する。変更要求(RFC)を起票し、影響範囲と切り戻し手順を書き、週次の CAB で審議し、承認されたものだけがメンテナンスウィンドウで適用される。開発(変更を作る側)と運用(安定を守る側)の分業は、この時代に制度として固まった。

変更は申請書と会議で統制する(CAB、1989)1周が1〜2週間。変更を減らすほど安全、という前提の上に立つ変更要求(RFC)を起票する影響範囲と切り戻し手順を書く週次の CAB承認するかメンテウィンドウで適用する差し戻し承認否認書き直して次週の会議へ

否認された変更は起票に戻り、次週の会議を待つ。このループが、変更を大きく溜める誘因になる。

合理的な設計だった。デプロイが年数回で、失敗の復旧に数日かかる世界では。1回の変更が大きく、戻すのが高いなら、変更の回数を減らして審査を厚くするのは正しい。だがこの統制モデルは「変更を減らすほど安全」という前提に立っており、前提が変わっても制度は残る。後に DORA がデータで反証することになる(第4部)。

greenfield の現在形: 3リスナー分離(external/admin/internal)は3層の子孫。ESB の教訓 → 賢さはエンドポイント(サービス)に置き、パイプ(SNS/SQS)は土管に保つ。Don Box のテネット3 → サービス間で共有するのは生成された client とスキーマだけで、実装の型は渡さない。CAB の40年後の姿 → 統制は申請書でなくアーキテクチャで表現する(apply 順序による承認)。