データモデリング - David Nuescheler のモデル data-modeling-david-nuescheler-s-model
ソース source
次の詳細は、David Nuescheler 氏が表明している見解です。
同氏は、アドビが 2010 年に買収した、グローバルなコンテンツ管理およびコンテンツインフラストラクチャソフトウェアの大手プロバイダーである Day Software AG 社の共同創立者兼 CTO です。現在は、アドビのフェローであり、Enterprise Technology のバイスプレジデントを務めます。また、コンテンツ管理の技術標準である Java™ コンテンツリポジトリ(JCR)アプリケーションプログラミングインターフェイス(API)、JSR-170 開発の第一人者でもあります。
詳しくは、https://cwiki.apache.org/confluence/display/jackrabbit/DavidsModel を参照してください。
David からのあいさつ introduction-from-david
様々な話し合いの中で、コンテンツのモデル化という点では、JCR の機能に関して開発者たちが幾分不安を感じていることがわかりました。リポジトリ内のコンテンツをモデル化する方法や、コンテンツモデルの中に優劣が存在する理由については、まだ何の指針もなく、経験もほとんどありません。
リレーショナルな世界では、ソフトウェア業界にはデータのモデル化に関して経験がありますが、コンテンツリポジトリに関しては、まだ初期段階です。
コンテンツをモデル化する方法について私の個人的意見を表明することにより、この空白を埋める試みを始めたいと思います。これがいずれ開発者コミュニティにとってより有意義なものへと変化し、単なる「私の意見」ではなく、より一般的なものとなることを期待しています。よって、これは私の最初の挑戦であり、今後急速に進化するものとお考えください。
簡単な 7 つのルール seven-simple-rules
ルール 1:データが第一、構造は二の次(おそらくですが)。 rule-data-first-structure-later-maybe
説明 explanation-1
ERD の意味では、宣言されているデータ構造について、最初のうちは、気にしないことをお勧めします。
開発の際は、nt:unstructured(およびその仲間)を好きになるようにしてください。
私の結論としては、構造はコストがかかるものであり、多くの場合、基になるストレージに対して構造を明示的に宣言することはまったく必要ありません。
アプリケーションで使用することになっている構造に関しては、暗黙の決まりがあります。例えば、ブログの投稿の変更日を lastModified プロパティに格納するとします。アプリケーションでは、その同じプロパティから再度変更日を読み取ることが自動的に認識されるので、明示的に宣言する必要はまったくありません。
必須などの追加のデータ制約や、タイプや値の制約は、データの整合性のために必要な場合にのみ適用します。
例 example-1
lastModified
日付プロパティを使った前述の例は「blog post」ノードの例であり、特別なノードタイプが必要であることを意味しているわけではありません。私は、少なくとも最初は必ず nt:unstructured
をブログ投稿ノード用に使います。私のブログアプリケーションでは、lastModified の日付を表示するだけなので(「order by」の場合もある)、それが Date であるかどうかはほとんど気にしません。私はブログを書くアプリケーションが「Date」を入れてくれることを暗黙的に信じているので、ノードタイプという形式で lastModified
日付の存在を宣言する必要は実際にはありません。
ルール 2:コンテンツ階層を推進し、成り行き任せにしない。 rule-drive-the-content-hierarchy-don-t-let-it-happen
説明 explanation-2
コンテンツ階層は非常に貴重なアセットです。したがって、成り行き任せにはせず、設計してください。人間が読み取れる「良い」ノード名がない場合は、それを考え直す必要があります。無作為の番号が「わかりやすい名前」になることはめったにありません。
既存のリレーショナルモデルをすぐに階層モデルに変換できれば簡単かもしれませんが、その際は多少の配慮が必要です。
私の経験では、アクセス制御および抑制によってコンテンツ階層を駆動させるという考えが多いようです。コンテンツ階層を、自分のファイルシステムと考えてください。ファイルやフォルダーを使用して、ローカルディスク上でモデル化することも可能です。
私は、個人的に、最初はノードタイピングシステム経由で階層を変換し、後からタイピングを導入する方法を好みます。
例 example-2
以下のような単純なブログシステムをモデル化します。この時点で使用する個々のノードタイプについて、最初は気にしません。
/content/myblog
/content/myblog/posts
/content/myblog/posts/what_i_learned_today
/content/myblog/posts/iphone_shipping
/content/myblog/comments/iphone_shipping/i_like_it_too
/content/myblog/comments/iphone_shipping/i_like_it_too/i_hate_it
ここで明らかになるのは、コンテンツの構造が、例に基づいて、追加説明なしで理解できることです。
「コメント(comments)」を「投稿(post)」と共に格納しないことを最初は疑問に思われるかもしれませんが、これは、合理的に階層化された方法でアクセス制御を適用したいからです。
上記のコンテンツモデルを使用すると、「匿名の」ユーザーにコメントの「作成」を簡単に許可する一方で、匿名のユーザーを残りのワークスペースで読み取り専用ベースに保つことができます。
ルール 3:ワークスペースは clone()、merge() および update() 用。 rule-workspaces-are-for-clone-merge-and-update
説明 explanation-3
アプリケーションで clone()
、merge()
、update()
などのメソッドも使用しない場合は、単一のワークスペースが有効な方法かもしれません。
「対応するノード」は、JCR 仕様で定義されている概念です。結局のところは、本質的に、それぞれ異なるいわゆるワークスペース内の、同じコンテンツを表すノードのことです。
JCR ではワークスペースの概念が抽象的に紹介されているので、何に使用すればよいのか、開発者には不明瞭なままになっています。ワークスペースを、以下のようにテスト目的で使用することを提案します。
「対応する」ノード(基本的には同じ UUID を持つノード)が、複数のワークスペースに多数重複している場合は、ワークスペースをうまく使用している可能性が高いでしょう。
同じ UUID を持つノードの重複がまったくない場合は、ワークスペースの使い方が誤っている可能性があります。
ワークスペースは、アクセス制御には使用しないでください。特定のユーザーグループにコンテンツを表示することは、別々のワークスペースに分割する十分な根拠とはなりません。JCR には、このためにコンテンツリポジトリの「アクセス制御」機能が用意されています。
ワークスペースは、参照およびクエリの境界です。
例 example-3
ワークスペースは、次のようなものに使用します。
- プロジェクトの v1.2 とプロジェクトの v1.3
- コンテンツの「開発」、「QA」および「公開済み」の状態
ワークスペースは、次のようなものには使用しないでください。
- ユーザーのホームディレクトリ
- 公開、非公開、ローカルなど、様々なターゲットオーディエンスの明確なコンテンツ
- 様々なユーザーのメールインボックス
ルール 4:同じ名前のきょうだいに注意。 rule-beware-of-same-name-siblings
説明 explanation-4
同じ名前のきょうだい(SNS)は、XML 用に設計され、XML で表現されているデータ構造との互換性を得るために仕様に導入されたので、JCR にとって有益ではありますが、リポジトリのオーバーヘッドが大きく、かなり複雑です。
いずれかのパスセグメントに SNS が含まれているコンテンツリポジトリのパスは、安定性が非常に低くなります。1 つの SNS が削除されるか並べ替えられると、その他すべての SNS およびそれぞれの子のパスに影響します。
XML の読み込みや既存の XML とのインタラクションのために SNS が必要かつ便利な場合もありますが、私はゼロから始めるデータモデルで SNS を使用したことがありません(今後も使用することはありません)。
例 example-4
使用方法
/content/myblog/posts/what_i_learned_today
/content/myblog/posts/iphone_shipping
以下の代わりに使用します。
/content/blog[1]/post[1]
/content/blog[1]/post[2]
ルール 5:参照は有害と見なされる。 rule-references-considered-harmful
説明 explanation-5
参照は参照整合性を暗示します。参照を使用すると、参照整合性を管理するリポジトリのコストが増加するだけでなく、コンテンツの柔軟性という点からもコストがかかることを理解することが重要です。
個人的に、私は、定まっていない参照をどうしても処理できない場合にのみ参照を使用し、それ以外の場合はパス、名前、文字列 UUID のいずれかを使用して別のノードを参照するようにしています。
例 example-5
ドキュメント(a)からドキュメント(b)への「参照」を許可すると仮定しましょう。参照プロパティを使用してこの関係をモデル化する場合、2 つのドキュメントはリポジトリレベルでリンクされるということです。参照プロパティのターゲットが存在しない可能性があるので、ドキュメント(a)の個別の書き出しや読み込みはできません。統合、更新、復元、クローンなど、その他の操作も同様に影響を受けます。
したがって、私はこれらの参照を「弱い参照」(JCR v1.0 では、結局のところターゲットノードの UUID を含む文字列プロパティ)としてモデル化するか、単純にパスを使用します。そもそも、パスのほうが有意である場合もあります。
参照が定まっていないとシステムが機能しない場合があると思いますが、私の実体験からは、十分に「現実的」でシンプルな例は思いつきません。
ルール 6:ファイルはファイルである。 rule-files-are-files
説明 explanation-6
コンテンツモデルがファイルまたはフォルダーのように感じられるものを見せている場合、私は nt:file
、nt:folder
、nt:resource
の使用(または拡張)を試みます。
私の経験では、多くの汎用アプリケーションで、nt:folder および nt:files とのインタラクションが暗黙的に許可されており、メタ情報が追加された場合にイベントを処理して表示する方法が認識されています。例えば、JCR をベースとしている CIFS や WebDAV のようなファイルサーバー実装との直接のインタラクションは暗黙となります。
私は経験則として、ファイル名と MIME タイプを保存する必要がある場合は、 nt:file
/ nt:resource
が良いマッチだと思います。複数の「ファイル」がある場合は、nt:folder は格納場所に適しています。
リソースのメタ情報を追加する必要がある場合(例えば、「author」プロパティや「description」プロパティなど)、nt:file
ではなく、nt:resource
を拡張します。nt:file を拡張することはほとんどなく、nt:resource
を頻繁に拡張します。
例 example-6
以下のブログに誰かが画像をアップロードすると仮定します。
/content/myblog/posts/iphone_shipping
最初の直感的反応は、画像を含むバイナリプロパティを追加することになるでしょう。
バイナリプロパティだけを使用する良い使用例もありますが(名前は重要でなく、MIME タイプは暗黙であるとします)、この場合、私のブログ例には、以下の構造をお勧めします。
/content/myblog/posts/iphone_shipping/attachments [nt:folder]
/content/myblog/posts/iphone_shipping/attachments/front.jpg [nt:file]
/content/myblog/posts/iphone_shipping/attachments/front.jpg/jcr:content [nt:resource]
ルール 7:ID は悪である。 rule-ids-are-evil
説明 explanation-7
リレーショナルデータベースでは、ID は関係を表すのに必要な手段なので、コンテンツモデルでも ID が使用される傾向があります。ただし、多くは誤った理由によるものです。
コンテンツモデルがプロパティでいっぱいで、「ID」で終わっている場合は、階層が適切に活用されていない可能性があります。
確かに、一部のノードでは、ライフサイクル全体に渡って安定した識別が必要です。そのようなノードは多くありません。ただし、mix:referenceable
によって、このようなメカニズムがリポジトリに組み込まれるので、安定した方法でノードを識別する方法を追加で考え出す必要はありません。
また、項目は、パスによって識別できることも、念頭に置いておきます。そして、UNIX® ファイルシステムで「シンボリックリンク」が多くのユーザーにとってハードリンクよりはるかに大きな意味を持つのと同様に、ターゲットノードを参照する場合は、ほとんどのアプリケーションでパスが意味を持ちます。
さらに重要なことは、mix:referenceable であるということです。つまり、本当に参照する必要がある時点でノードに適用できるということです。
つまり、タイプが「ドキュメント」であるノードを参照可能にしたいからといって、「ドキュメント」ノードタイプを静的な方法で mix:referenceable
から拡張しなければならないということにはなりません。これは、「ドキュメント」の任意のインスタンスに動的に追加できるからです。
例 example-7
使用方法:
/content/myblog/posts/iphone_shipping/attachments/front.jpg
以下の代わりに使用します。
[Blog]
-- blogId
-- author
[Post]
-- postId
-- blogId
-- title
-- text
-- date
[Attachment]
-- attachmentId
-- postId
-- filename
+ resource (nt:resource)