こまどブログ

技術のこととか仕事のこととか。

『データ指向アプリケーションデザイン』を読む(3):2章「データモデルとクエリ言語」

『データ指向アプリケーションデザイン』の2章「データモデルとクエリ言語」についての読書メモ。

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

データモデルと抽象化

前章に続いて、抽象化というキーワードが出てくる。

それぞれのレイヤーはクリーンなデータモデルを提供することによって下位のレイヤーの複雑さを隠蔽してくれています。こうした抽象化によって、たとえばデータベースベンダーのエンジニアや、そのデータベースを使うアプリケーション開発者など、様々なグループの人々が効率的に共同で作業できるのです。*1

各言語(自分が念頭に置いているのはJavaだが)コレクションを取り扱うライブラリや、それを更に隠蔽したファーストクラスコレクションは、下位レイヤーの隠蔽のわかりやすい例だと言えるのではないか。インピーダンスミスマッチはこの文脈では言及されていないが、隠蔽が極めて複雑な仕方で行わなくてはならない異なるデータモデル同士の関係を言うものと理解できると思う。

ドキュメントモデル

ドキュメント型のデータモデルについて、紙幅を割いてその特徴を論じている。本文中では、ドキュメント型木構造が明示されている(それゆえ、個人の履歴書のような構造のデータには親和的である)ことや*2、ドキュメントデータベースの多くで結合のサポートが弱いこと*3が指摘されている。しかし、この書籍の特徴的な態度でもあるが、異質なものと理解されている複数のものをわかりやすく対比させるだけでは終わらずに、共通性や中間的なあり方についても言及している。たとえば、多対一や多対多の関係の表現において、リレーショナルデータベースでもドキュメントデータベースでも識別子による参照(外部キー、ドキュメント参照)が行われるという指摘などである*4

アプリケーションにおけるドキュメントモデルの利用については、以下のような原則を示しながらも、別の箇所では、「仮にアプリケーションの初期バージョンが結合が不要なドキュメントモデルにうまく適合したとしても、アプリケーションに機能が追加されていくにつれて、データ同士はつながりを持つようになるものです。」*5と指摘している。ドキュメント型に適合している例として挙げられた履歴書の情報が、どのようにドキュメント型の枠を超えてくるかという説明もわかりやすい。

アプリケーションのデータがドキュメントのような構造を持っている(すなわち一対多の関係からなるツリー構造を持ち、通常はそのツリー全体が一度にロードされる)なら、おそらくはドキュメントモデルを利用するのは良い考えです。リレーショナルな手法である細分化(shredding)、すなわちドキュメントのような構造を複数のテーブルに分割することによって、スキーマが込み入ったものになり、アプリケーションのコードが不必要に複雑になることがあります。*6

ドキュメントモデルの特徴であるローカリティについては以下のような指摘もなされている。大きなデータを一箇所にまとめておくことで一度に全体を取れるというメリットが、ドキュメントのサイズを大きくすること自体によるデメリットゆえに実際に享受しにくくなっているというのは面白い現象で、同種の事態はデータモデル以外の文脈でも見られるのではないだろうか。設計を考える際には頭の隅に置いておきたい。

ローカリティのメリットが生じるのは、一度のドキュメントの大部分が必要になる場合に限られます。通常、ドキュメントの一部にしかアクセスしない場合でも、データベースはドキュメント全体をロードしなければならず、これはドキュメントが大きければかなり無駄になるかもしれません。ドキュメントを更新する場合には、通常ドキュメント全体を書き直さなければなりません。変更の処理をその場所でデータを上書きして済ませられるのは、エンコード後のドキュメントのサイズが変わらない場合だけです。そのため、概してドキュメントは小さく保ち、ドキュメントのサイズを大きくするような書き込みは避けることが望ましいです。こうしたパフォーマンスの制約があるため、ドキュメントデータベースが有効になる状況はかなり減ってしまいます。*7

クエリ言語とグラフ型データモデル

様々なクエリ言語を紹介しながら、それぞれの特徴を記載している。大きく取り上げられているのは、宣言的言語、APIの魅力である。並列処理への適合性という文脈で宣言型を語るのはJavaにおけるforループとStream APIの違いなどと同じだ。また、書籍中ではスタイルの適用におけるCSSJavaScriptの違いも宣言型/命令型という文脈で捉えられている。具体的な例を挙げて両者の違いが影響を及ぼす理屈を説明していてわかりやすい。

宣言的な言語が魅力的なのは、通常それが命令型のAPIに比べて簡潔で、扱いやすいためです。しかしもっと重要なのは、それがデータベースエンジンの実装の詳細も隠蔽してくれることであり、そのおかげでクエリの書き換えなしにデータベースシステムはパフォーマンスを改善できるのです。(中略)最後に、宣言型の言語は並列実行に向いていることがよくあります。今日では、CPUの高速化はクロックを高速にするのではなく、コア数を増やすことによって達成されています。*8

クエリ言語と併せて細かく論じられているのはグラフ型のデータモデルについてだ。多対多のデータの関連が支配的になってきた場合には、ドキュメント型やリレーション型ではなくグラフ型のデータモデルが親和的になる。グラフ型のデータモデルには個人的に馴染みがなく、CypherやSPARQLといった、書籍中で紹介されているクエリ言語も知らないものばかりだった。SQLにおける再帰共通テーブル式WITH RECURSIVE)もグラフ型データモデルの文脈に位置付けられている。

これまでに、多対多の関係が様々なデータモデルの重要な機能の差異になっていることを見ました。アプリケーションの持つ関係のほとんどが一対多(ツリー構造)だったり、レコード同士が関係を持ったりしないのであれば、ドキュメントモデルが適しています。しかし、データ中で多対多の関係が一般的だった場合はどうでしょうか?リレーションモデルは多対多の単純なケースは扱えますが、データ同士の繋がりが複雑になっていくと、データをグラフとしてモデル化するほうが自然になっていきます。*9

上の一節では、関連の観点からドキュメント→リレーショナル→グラフという展開が示されている。のちの部分では、階層型の欠点を補うものだったリレーショナルモデルのあとに、「NoSQL」という括り方をされるものの方向性を異にする二つのものとして、関係の取り扱いを重視しないドキュメントモデルと、複雑な関係を取り扱うのに適したグラフモデルが登場したという歴史的な展開が示されている*10

スキーマレス」を巡って

データモデルを語る際にしばしば使われる「スキーマレス」の概念についても、わかりやすい説明がなされていた。以下の一節では、ドキュメントデータベースにおける「スキーマレス」(=スキーマオンリード)と、リレーショナルモデルにおけるスキーマオンライトとの対立を、プログラミング言語における動的型付けと静的型付けとの対立と類比させている。言われてみるとなるほどと思わされる説明である。

ドキュメントデータベースはしばしばスキーマレスだと言われますが、これは誤解を招く表現です。なぜなら通常、データを読み取るコードは何らかの構造があることを前提とするからです。もっと正確な言葉を使うなら、これはスキーマオンリード(データ構造は暗黙のものであり、データの読み取り時にのみ解釈される)であり、スキーマオンライト(リレーショナルデータベースにおける伝統的なアプローチであり、スキーマは明示され、データベースは書き込まれるすべてのデータがそのスキーマに従っていることを保証する)の逆です。スキーマオンリードは、プログラミング言語における動的(実行時の)型チェックに似ており、一方でスキーマオンライトは静的(コンパイル時の)型チェックに似ています。*11

感想

抽象化や宣言型、それに最後のスキーマと型付けの話など、この書籍では、アプリケーションのプログラミングの領域で馴染みのある物事の捉え方が、データモデルやクエリの領域にもうまく適用されているような印象を持つ。これまで主にアプリケーションの内部の設計やコードの記述方法について勉強する中で身につけてきた考え方が他の領域にも活かせる、ということを感じさせてくれ、勇気付けられる。抽象的になりすぎずに具体的な事例を交えつつこのような議論ができるというのは、経験と思考が高度に組み合わさっていてこそだと思われ、著者に対しては畏敬の念を禁じ得ない。

*1:30ページ。

*2:33ページ。

*3:36ページ。

*4:40ページ。

*5:36ページ。

*6:41ページ。

*7:44ページ。

*8:46ページ。

*9:51ページ。

*10:65ページ。

*11:42ページ。

『データ指向アプリケーションデザイン』を読む(2):1章「信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション」

『データ指向アプリケーションデザイン』の1章「信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション」についての読書メモ。

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

導入

全体の導入となる章。前回の記事でも引用が、タイトルにも現れている「データ指向アプリケーション」を以下のように提示するところから始まる。

今日の多くのアプリケーションは、演算指向ではなくデータ指向であり、CPUの処理能力そのものが制約条件になることはほとんどありません。通常は、データの量や複雑さ、そしてデータの変化する速度のほうが大きな問題なのです。*1

上記の意味での「データ指向」なアプリケーションを構築するに当たって、重要な課題になるのが、「信頼性」、「スケーラビリティ」、「メンテナンス性」の3つの性質だとされる。著者は、よく使われるこれらの概念が、「はっきりと意味が理解されることなく使われてい」ることを問題視し、1章を丸々これらの概念についての考え方を説明するのに費やす。

信頼性

信頼性は、「何か問題が生じたとしても正しく動作し続けること」とまとめられる。複数のコンポーネントから成るシステムでは、仕様を満たしていないコンポーネントとしてのフォールトの存在が、システム全体の適切なサービスの停止(=障害)に至らないようにしておくことが課題になる。著者は、フォールトの所在として、ハードウェア、ソフトウェア、そして人間を挙げる。

ハードウェアのフォールトからシステムを守る手段として、従来は冗長化が支配的であったが、現在ではそれに加えてソフトウェア側でもハードウェアのフォールトに対応できるような手法を採用することが増えているという。大量のマシンを利用するようになっていること、(それを可能にした)クラウドプラットフォームの仮想マシンが単一マシンの信頼性を最重要視していないことと行ったシステムを環る状況の変化が、耐障害性を確保するための手法にも影響を与えているというのだ*2

ソフトウェアについては、ハードウェアにおけるフォールトとの性質の違いが言及される。ハードウェアのフォールトが、複数のマシンで同時に発生するような性質を有することが稀であるのに対して、ソフトウェアのフォールトは相関をもった形で現れることがあり、障害に繋がりやすいという。このようなフォールトには「手っ取り早い解決策」はないとしながらも、システムに関する前提を注意深く考えることやプロセスの分離などの処方箋が提示される*3

最後の「人間」についての節では、「最大限に努力しても、人間には信頼性がないことが知られています*4」という厳然たる事実から出発し、これに対処するためのアプローチをいくつか挙げている。それらの中には、「『正しいことを』行いやすく、『間違ったこと』を行いにくくしてくれる」インタフェースをうまく設計することも挙げられている。『プログラマの知るべき97のこと』に書かれていることではあるが、「人間の信頼性」という観点でハードウェアやソフトウェアのフォールトと並べた文脈で現れたのは新鮮だった。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

スケーラビリティ

スケーラビリティについては、冒頭に書かれていたことが印象に残った。そのまま引用する。

スケーラビリティとは、負荷の増大に対してシステムが対応できる能力のことを指して使われる言葉です。ただし、これはシステムに対して与えることができる1次元のラベルではないことに注意してください。「Xはスケーラブルである」あるいは「Yはスケールしない」などと言うことに意味はありません。*5

自分の現職は、基本的にデータの量や複雑さがあらかじめ予測できる業務システムを開発していて、「スケーラビリティ」という言葉を社内で聞くことはあまりない。言葉は知っているものの、「あー、クラウドでマシンを横に複数並べたり大きくしたりして得るやつね」というくらいの認識しかなく、まさに一次元で捉えていたことを気付かされた。

さて、スケーラビリティを考えるに当たっては、対処すべき負荷と、その負荷によって影響を受けるパフォーマンスを具体的に特定することが必要で、そのためには負荷とパフォーマンスをどのように表現するかが重要だと著者は指摘する。特定の種類の負荷に対応することを企図したアーキテクチャは、別の種類の負荷に対応するためのアーキテクチャとは全く異なっているのであり、全てに対応できる「魔法のスケーリングソース」は存在しないということを頭に入れておく必要がある。

負荷の表現の説明で挙げられているTwitterの例はとてもわかりやすく、かつ面白い。また、パフォーマンスの表現でパーセンタイルを使うことを推奨しているのは、金融のリスク管理分野に縁がある自分にとってはスムーズに受け入れられた。「見積もりは確率分布で考えよう」というのと同じく、広く知られていい考え方ではないだろうか。

また、コラムの「レイテンシとレスポンスタイム」についての説明は、今まで自分がちゃんと区別できていなかったことを明確に区別していて役に立った。

レスポンスタイムはクライアントから見た値であり、リクエストの処理そのものに費やされた時間(サービスタイム)に加えて、ネットワークやキューイングによる遅延が含まれます。レイテンシは、リクエストが処理を待っている時間であり、リクエストはこの期間待ち状態にあり、サービスを待っています。*6

メンテナンス性

メンテナンスのためのコストを最小化するための設計原理として、運用性、単純性、進化性の3つが挙げられる。

運用性の高いシステムとは、システムが運用チームにとって取り扱いやすいことである。運用性についての記述では、運用チームの責任範囲や彼らの定型タスクを容易にするデータシステムにおけるプラクティスが例示される。後者として指摘されているものは、データシステムに限定したものというよりは、運用に配慮したシステムを作る際に考慮すべき点のリストとなっている。

単純性は、ここではエンジニアにとっての理解しやすさであり、ユーザインタフェースの単純さではないと明確に断っている。実装の複雑さが及ぼす悪影響についての参考文献として、ブルックス『人月の神話』とRich Hickeyの"Simple made Easy"が並んで脚注に載せられているのが印象的だ。複雑さを取り除くための一つの考え方として、「偶発的な複雑さ」という概念が紹介される。

システムを単純にすることは、必ずしも機能を減らすということではありません。単純にするということは、偶発的な複雑さを取り除くということでもあります。MoseleyとMarksは[32]*7、偶発的な複雑さについて、「ソフトウェアが解決しようとしている(ユーザーから見た)問題がもともとは持っておらず、実装からのみ生じている複雑さ」と定義しています。*8

偶発的な複雑さを取り除くための有力な手段として提示されるのが「抽象化」である。実装の詳細をわかりやすいインタフェースの裏側に隠す優れた抽象化が、それを利用するエンジニアにとっては大きな助けになる。抽象化の意義として再利用性が挙げられる場合もあり、この書籍でもそれは指摘されているが、個人的には抽象化の第一の意義は隠蔽であると考えている*9

なお、実装の単純さというと、"Worse is Better"、MIT approach と New-Jersey style との対比が想起される。この辺りは以下が参考になる。

ajito.fm

note.mu

進化性については、この章ではあまり紙幅が割かれていないが、重要な指摘がされている。 システムに対する要求の変化に対応するためのアプローチとして、アジャイルのコミュニティが、これまでテスト駆動開発リファクタリングあなどを提案してきたしてきたが、それはシステム全体の中のごく小さな、ローカルなスケールでの変更を支援すルものだったという。より大きなアーキテクチャのレベルでの「リファクタリング」を可能にするためにどうすればよいか、というのは未解決の課題として残されているというのである。著者は、このレベルでの変化への対応しやすさを、「進化性」と名付けて論じることを予告する。

感想

読んでいて、「そうそう、それそれ」という納得と「なるほど!そうなのか!」という気づきとがひたすら連続する。常識的な事柄も丁寧に説明されている一方で、優れた洞察も随所に散りばめられていて、学ぶことの多い。このような記事を書いておいて言うのも憚られるのだが、一文一文に知見が込められているので、要約してしまうと魅力が失せてしまう本だと思う。

読み方にしても、一回読んで終わりというよりは、なんども繰り返して読む、折に触れて必要な箇所を読み直すという読み方をすることによって、自分の知識や経験の蓄積、その時々の現場での悩みに応じて得られるものがあるのではないかと思う。

*1:3ページ。

*2:8ページ。

*3:9ページ。

*4:9ページ。

*5:11ページ。

*6:15ページ。

*7:Ben Moseley and Peter Marks: "Out of the Tar Pit," at BCS Software Practice Advancement, 2006.

*8:22ページ。

*9:このあたりは『Code Complete』に影響を受けている。

『データ指向アプリケーションデザイン』を読む(1):タイトルについて

『データ指向アプリケーションデザイン』を読み始めた。本文だけで605ページという大著なので、少しずつ読み進めていきたい。

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

データ指向アプリケーションデザイン ―信頼性、拡張性、保守性の高い分散システム設計の原理

  • 第I部 データシステムの基礎(1〜154ページ)
    • 1章 信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション(3〜27ページ)
    • 2章 データモデルとクエリ言語(29〜71ページ)
    • 3章 ストレージと抽出(72〜117ページ)
    • 4章 エンコーディングと進化(119〜154ページ)
  • 第II部 分散データ(155〜422ページ)
    • 5章 レプリケーション(161〜213ページ)
    • 6章 パーティショニング(215〜237ページ)
    • 7章 トランザクション(239〜295ページ)
    • 8章 分散システムの問題(297〜349ページ)
    • 9章 一貫性と合意(351〜422ページ)
  • 第III部 導出データ(423〜605ページ)
    • 10章 バッチ処理(427〜479ページ)
    • 11章 ストリーム処理(481〜535ページ)
    • 12章 データシステムの将来(537〜605ページ)

XX-oriented vs XX-intensive

「〇〇指向△△」というと、原題は「〇〇-oriented △△」だろうかと想像するが、この本の原題は、「Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems」である。

まず気がつくのが、「データ指向」がDate-orientedの訳語ではなくData-intensiveであるということだ。この"intensive"の語感は、「labor-intensive(労働集約的)」というときのintensiveに近いものだと思われる。つまり、アプリケーションのなかの相対的に重要な位置をデータが占めているということだ。本文中の以下の記述には、演算指向(compute-intensive)、つまり演算(計算処理)が中心となるアプリケーションとの対比が表現されている。

今日の多くのアプリケーションは、演算指向ではなくデータ指向であり、CPUの処理能力そのものが制約条件になることはほとんどありません。通常は、データの量や複雑さ、そしてデータの変化する速度のほうが大きな問題なのです。*1

オブジェクト指向(Object-oriented)」が分析なり設計なりプログラミングなりの「中心にオブジェクトを据えていきましょう」という方向性を示しているものであるのに対して、「データ指向(Data-intensive)」は事実としてデータが重要な位置付けを占めているということを表現しているということができるだろう。それは、「労働集約型産業(Labor-intensive industry)」が「労働を中心に据えてやっていこうな」という話ではないというのと同じだ。

「データ指向アプリケーションデザイン」は手法ではない

上述の点と関連して、押さえておかなければならないのは、「Data-intensive」という形容詞が、「Application」にかかっているということである。つまり、本書が語る対象は、「<データ指向な><アプリケーション設計>」ではなく、「<データ指向アプリケーション>の<設計>」なのである。

この書籍の主眼は、先述の意味で「データ指向なアプリケーション」をどのように「設計」すべきかという点に置かれている。「デザイン」と訳されている原題の語は「Designing」(動名詞)であり、たとえば『エリック・エヴァンスのドメイン駆動設計(Domain-Driven Desgin)』における名詞の「Design」とは異なっている。後者が設計の手法であるのに対して、前者は設計という営み自体である。

内容に照らしてみても、本書は「データ指向アプリケーションデザイン」という設計手法の考案・提唱を目的としたものではない。したがって、「DDDで設計してみました」はありえても*2、「データ指向アプリケーションデザインで設計してみました」ということはない。

技術書の邦題問題

以上、『データ指向アプリケーションデザイン』のタイトルについて考えてきた。自分の考察が適切であるとすれば、本書の邦題はややピンぼけしているように思う。しかし、それは訳者に帰する問題ではおそらくないし、批判しようという意図はない。

テスト駆動開発』をオーム社から再出版するときに、「入門」とタイトルに入れたがる出版社サイドを、訳者のt-wadaさんが制したという。「入門」や「実践」が入るとよく売れるという出版事情があるようで、それは自分の知っている書籍にも影響を与えているように思う*3。それ以外にも、シリーズらしく見えるように邦題を設定したり、さまざまな制約が邦題というものにはあるのだろう。

読者コミュニティの一員としてできるのは、このような大著を母語で読める形で世に出してくれた訳者や出版社に敬意を評しつつ、より良くその書籍を読むアイデアをコミュニティに提出していくことなのではないかと思う。

*1:『データ指向アプリケーションデザイン』3ページ。

*2:ただ、「DDDで設計してみました」にはその他の理由でマサカリが飛ぶことはあろう。

*3:『実践ドメイン駆動設計』や『実践テスト駆動開発』など。