パート1 このデータモデルの目的
数年前のことです。私はある依頼元から、一風変わった難題を突きつけられました。最終的なデータベース構造をはっきりさせないままで、データベースアプリケーションをデザインしてほしいというのです。
妙な注文ですよね。背景をもう少し説明すれば、多少は話が見えてくるかと思います。
その依頼元は、顧客向けの情報を大量に保持、管理、および生成するためのシステムを必要としていました。顧客たちがデータへアクセスするときには専用のクライアントアプリケーションを使用するのですが、このアプリケーションは継続的に変更される見通しでした。クライアントアプリケーションとバックエンドシステムの間のインターフェイスにはSQLファイルを使用します。それによって、独自のクライアントデータベースを読み込むという形です。
クライアントの数は、当面は数万程度と予想され、5年以内には数十万のレベルに増加するものと見込まれていました。それぞれのクライアントに対して、毎日のように更新や修正が必要となる可能性もあります。このようなデザイン要件を満たさなくてはならないという、一風変わった難題だったのです。
最初に考えたのは、「いったいどうやって実現すればいいのか」ということです。
従来どおりのやり方でデータベースをデザインし、その時点で判明している属性をすべて定義したうえで、そのデザインに基づいてアプリケーションを構築するという手もなくはありません。しかし、そこで問題となるのは、クライアントアプリケーションが継続的に変更されるのに合わせて、データベースアプリケーションにも変更が必要になる可能性が高いという点でした。我が社の開発チームが今後5年間多忙になるという意味ではけっこうなことですが、顧客には決して了解してもらえそうにありません。
我々が必要とするシステムは、データベースに何を格納するかや、システムとやり取りされるデータに対してアプリケーションでどのような処理を行うかを顧客が自ら管理できるようなシステムでした。しかも、顧客がアプリケーションに些細な変更を加えるたびに、我々開発者に問い合わせなくても済むようにする必要がありました。
とても簡単には済まない話です。
そこで我々は、規則ベースのデータベースエンジンをデザインすることにしました。規則ベースのシステムは、きちんと固まっているシステムよりも複雑な(つまり高くつく)ものではありますが、時間の経過とともにビジネスルールが変わったときにユーザーが必要な対応を施すことができるため、長い目で見ると、顧客側のコストは安くなります。
規則ベースのデータベースエンジン
「規則ベースのデータベースエンジン」とは、データベースに格納されたデータだけでなく、「データについてのデータ」を定義するメタデータも併せ持つシステムです。このメタデータによって、追加的な情報を定義しておくことができます。アプリケーションは、その情報を解釈して、各部分の別個の情報が互いにどのように関係しているかを把握します。ある意味では、プロパティとメソッドがすべてデータベース内に格納されているようなものです。
一般に、正規化されていないデータベースの場合、データモデルとデータは図1のようになります。
ここでは、項目に関連付けられているすべてのデータが、同じ「マスターレコード」に格納されています。この形を使用することには大きなメリットがあります。最大のメリットは、データアクセスの速度です。この形の実装では、項目に対応するすべてのデータを、1回のデータベース呼び出しで確実に取得できます。コストのかかるインデックスやその他のオーバーヘッドは不要です。
一方、デメリットとなるのは、レコードの属性に変更を加える場合、データベース管理者(DBA)が、テーブルレコードのデータ構造に修正を加える必要があるという点です。その場合、通常は、当該のデータを参照するアプリケーションのコードにも変更を加えることになります。
図2に示すのは、メタデータの概念を使用して正規化されたデータベースの基本的なデータモデルです。ここで言う「マスターレコード」が、参照するメインの項目です。
たとえば、椅子についての情報を保持するデータベースだとしましょう。その場合、マスターレコードは、個々の椅子を表します。これにはIDが与えられ、おそらくは名前も与えられます。また、作成日や作成者なども、このマスターレコードで管理できます。
それ以外の項目はすべて、属性として格納されています。椅子そのものについて、色、種類、材質、場所などの属性を格納できます。
これらの椅子について把握できる項目が、最初の時点ですべて明確になっているのであれば、正規化されていない方法でも問題ありません。その場合、データテーブルは「図3:正規化されていないテーブルデータ」のようなものになります。開発者の観点から言うと、これはアクセスや操作が簡単です。また、速度面でもメリットがあります。データベースを1回呼び出すだけで、椅子についてのデータをすべて取得できるからです。
しかしここで、このデザインでそもそも問題となっているのは何かを思い出してみましょう。この先5年のうちに、椅子の属性がどうなるかわからないということでした。そのようなテーブルをどのようにデザインすればいいでしょうか。
「図2:正規化されたデータモデル」では、動的な属性を使用した実装方法を示しました。その方法を使えば、椅子自体への参照とその属性を別々に格納できます。保持すべき新しい属性が出てきた場合には、その属性のメタデータを定義すれば、属性テーブルにその属性を保存できます。
上記の例では、IDを使用して項目が互いに関連付けられていることがわかります。
この例では、tblChairテーブルは、IDのみを保持する簡略なものとなっていますが、そのIDは、tblChair_attributeテーブルのCHAIR_ID列で参照されています。これは、どの椅子についてのデータなのかを示します。また、ATTRIBUTE_TYPE_ID列は、tblAttribute_metadataテーブルのどの項目を表すデータなのかを示します。
さらには、メタデータテーブルを拡張して、既定値や、特定の属性に固有の属性値などを持たせることもできます。次の記事では、アプリケーションがデータを処理するときに的確な判断を行えるようにするために使用するさまざまな項目について説明します。
データへのアクセス
これで、基になるデータモデルのデザインは完了しました。これを見て、「このモデルはけっこうだが、このように拡散したデータでは、アクセスやメンテナンスは面倒そうだ」と思っている人もいるかもしれません。
しかし幸いなことに、現在のデータベースエンジンでは、さまざまなアクセス手法を用いることで、開発者の苦労を軽減できるようになっています。あらかじめ定義しておいたクエリやプロシージャを使用すれば、正規化されたデータモデルで項目を参照、編集、削除したい場合にも、開発者は簡単に対応できます。
正規化されていないテーブルの場合は、単純なSQL SELECTステートメントを呼び出してデータにアクセスしさえすれば、うまくいきます。一方、正規化されたデータの場合は、データの上位にインターフェイス層を作成して、アプリケーション自体からのアクセスにはその層を使用するのが理にかなっています。
その手法として最もよくあるのは、データベース内に作成したストアドプロシージャを使用する方法です。名前付け規則を標準化すれば、モデル内のデータを処理するときに使用すべきインターフェイスを開発者が理解しやすくなります。ここでは、マスターテーブルの項目名(つまりchair)の後にメイン項目のアクションを付加するか、または、マスターテーブルの項目名の後に_attributeと付加し、さらにその後ろにアクションを付加する、というのを名前付け規則とします。
- <mastertable>_get -- つまりchair_get
- <mastertable>_update -- つまりchair_update
- <mastertable>_insert -- つまりchair_insert
- <mastertable>_delete -- つまりchair_delete
- <mastertable>_attribute_get -- つまりchair_attribute_get
- <mastertable>_attribute_update -- つまりchair_attribute_update
- <mastertable>_attribute_insert -- つまりchair_attribute_insert
- <mastertable>_attribute_delete -- つまりchair_attribute_delete
こうしたさまざまなプロシージャが実行する処理の詳細や、メタデータが複雑な場合にこれらのプロシージャを拡張して検査や評価を行う方法の詳細については、今後の記事で解説します。
一方、これらのプロシージャによって、開発者は、データベースのデータに簡単かつシームレスにアクセスできます。データモデルやマスター項目の属性(上記の例で言えば、これまではなかった新しい椅子の属性など)に変更が加わった場合には、開発者のコードでそれらの変更に対応でき、新しいユーザーインターフェイスやビジネスルールを作成する必要はありません。
この手法で鍵となっているのは、データベースを読み込んだうえで各項目の定義を判断するようにアプリケーションをデザインするということです。まずは汎用的な項目(上記の例なら椅子)を定義しておきます。次に、データベースをクエリして、椅子の定義がどうなっているかを判断します。その後で、アプリケーションでその情報を表示して、参照や編集を行えるようにします。また、この手法では、表示や制約条件に関する情報もデータモデルに保持できます。項目を適切に表示したり、顧客が望む要件に合致させたりできるようにするためです。
今後のいくつかの記事では、T-SQLおよびASP.NETを使用してこれをデザインする方法を説明します。そうすれば、動的な変更に対応できるようになります。
システムのメンテナンス
「ここまでの話はどれもたいへんけっこうだが、開発者がビーチでバカンスを楽しんでいて連絡が取れないようなときでも、システムの拡張が滞らないようにするには、どうしたらいいんだ?」と思っている人もいるかもしれません。その答えは、メタデータテーブルを操作するためのインターフェイスを用意するということです。それにより、顧客はさまざまな属性の追加や削除、さらに場合によっては隠蔽も実行できます。
これら一連のテーブルに対する「管理者」権限をエンドユーザーに与えれば、アプリケーションコードの実装に応じた制約の範囲内で、ユーザーはデータモデルに項目を追加または削除できます。
我々は、これらのテーブルに対するWebインターフェイスを顧客向けに開発しました。これにより顧客は、マスター項目(椅子など)に対して新しい属性をすばやく追加でき、エンドユーザーインターフェイスを通じて表示および管理できます。さらには、複雑な条件や検索テーブルにも、新しいアプリケーションコードの作成なしで対応できます。
以上を全部ひっくるめて考えると、結局のところ、静的なデータモデルをデザインするのに比べて、複雑さが増し、最初の時点で要する時間も長くなりましたが、最終的には、開発者がいなくても顧客が自分でアプリケーションを自由にメンテナンスできるようになりました。
それが朗報と言えるかどうかはさておき、顧客が事情を理解してくれて、次の仕事でまた声をかけてくれることを期待しましょう。
今後の展開
次回の記事では、データモデルのデザインや、データベースでの制約の処理の詳細について取り上げます。また、Visual Studio 2003とSQL Server 2000に用意されているツールを使用してこれを実装する方法も取り上げます。
さらに、Visual Studioでの型クラスによるアーキテクチャの実装に話を進め、これらの未知の属性をアプリケーションで表示できるようにするための動的なインターフェイスの開発に取り組みます。
また、管理インターフェイスの基本も取り上げます。その中で、Visual Studioに組み込まれている強力な機能とその活用方法にも触れます。
最後に、.NETの枠を超えてこのアーキテクチャを拡張する方法について述べます。データベースの威力を最大限に活用することで、.NETでない補助的なアプリケーションを開発できました。しかし、特定のアプリケーションに依存しないようにシステムをデザインしたため、データ整合性は引き続き維持されています。