オブジェクト指向的なアクセスもSQLによるアクセスもできる便利さ
インターシステムズのデータベースの実体は、プログラミング言語の変数(グローバル変数と呼びます)であると前回説明しました。これは言い換えるとプログラミングによって必要なデータ構造の構築を行うことであり、一般的なデータベースで事前に必要なスキーマ(ディクショナリー、リポジトリなどと言われることもあります)の構築が必要ないことを意味します。
しかしスキーマ定義が必要ないというのは、変化が激しいデータ構造を取り扱う時やデータモデルがあらかじめ定まらない中で試行錯誤しながらデータ構造を構築していく場合や、ライフサイクルが比較的短くちょっとした中間データ構造を定義したい場合などには柔軟に対応でき便利な面もあります。しかし、ある程度安定したデータ構造を処理する際には、スキーマがあったほうがデータ構造を理解しやすく、管理もしやすいでしょう。さらに、この構造は外部システムにとっては全く理解不能なものなので、外部システムとデータ交換する際には何らかのスキーマ情報を構築してデータのやり取りを行う必要があります。
この要件を満たすために考案されたのが、統一データアーキテクチャです。この「統一」という言葉はオブジェクト指向的なアクセスと、リレーショナル(SQL)的なアクセスを統一することを意味しています。インターシステムズが統一データアーキテクチャを考案する際、当時すでに主流だったリレーショナルアクセスの概念を取り込むことは当然でしたが、一方プログラミング手法として着実に浸透してきたオブジェクト指向プログラミングとリレーショナルデータベースの相性の悪さ(O/Rマッピング)をなんとか解消したいという考えがありました。
諸悪の根源はオブジェクトのスキーマ定義とリレーショナルのスキーマ定義を、別々に作ってそれをマッピングさせる方法にあります。スキーマを一度定義したあとで、変化しないのであれば難しい問題はありません。しかし、さまざまな理由でスキーマは変化していくものです。そうすると、変化のたびにオブジェクトの定義、リレーショナルの定義、さらにそれらをマッピングする定義を維持、更新していかなければなりません。これは、想像以上に煩雑で手間のかかる作業なのです。
統一データアーキテクチャでは、クラス定義というスキーマ定義を行うとそれに基づくオブジェクト構造のスキーマと2次元のテーブルのスキーマ(複数テーブルに分解されることもある)、および最終的にデータが格納されるストレージのグローバル変数の格納構造を自動的に生成します。スキーマを変更する際には、クラス定義を変更するだけでOKです。内部の関連する変更は、システムが自動的に維持管理してくれます。
リレーショナルデータベースとオブジェクト指向の相性が悪いもう1つの側面は、処理の効率性の問題です。リレーショナルデータベースの強みは、データを最小単位(2次元のテーブル)に分割し、集合論に基づく演算でいかなる複雑な構造も表現できることが数学的に証明されている点です。一方で、処理の効率性というものは概念上は全く考慮されていません。構造というものを極力排除することで、さまざまな角度からデータを参照できる柔軟性が得られるわけですが、その柔軟性を得るためのコストが余計にかかっているとも言えます。
これに対してオブジェクト指向でのデータモデリングでは、世の中の事象をあるがままに捉えることが優先されます。従ってそのデータ構造には繰り返しや入れ子、入れ子の入れ子など、複雑な構造のサポートが必要です。これらの複雑な構造をリレーショナルデータベースで実現しようとすると、複数のテーブルを結合し必要なデータを取得して、その対象オブジェクトにデータを項目別に転送する処理が必要です。O/Rマッパーと呼ばれるフレームワークで、これらの一連の面倒くさい処理はある程度自動化できますが、実行時の効率の悪さは解消困難です。
一方、インターシステムズのグローバル変数は、別名多次元データ配列とも呼ばれ、複雑な構造を自然な形で表現可能です。そのため、オブジェクトが必要とする構造に簡単にプロジェクション(写像化)ができるのです。複雑な構造を表現可能ということは、単純な構造である2次元のテーブルも簡単に表現できます。この統一データアーキテクチャによって、データベースに対しオブジェクト指向の考え方に基づくアクセスとリレーショナル的なアクセスを両立させることが可能になります。しかもこれらのアクセスは、排他的ではなく混在させることも自由です。
実際実用的なアプリケーションでは、オブジェクトインターフェイスだけですべての処理が実現できることはまれです。ある条件に合致するオブジェクトの集合を取得する際には、SQLを利用した条件検索のほうが簡単にやりたいことを実現できます。また、取得したオブジェクトとその他のオブジェクトの関連を処理する場合やリストや入れ子構造を処理する際には、オブジェクトのインターフェイスを使ったほうがずっと効率良く処理できます。