テーブル設計 "いやな臭い"

Scott Ambler の Refactoring Databases から

次のような現象を発見したら、データベースのリファクタリングを考える。
テーブル設計の再検討が必要。

・多目的に使われるカラム
・多目的に使われるテーブル
・重複したデータが別がテーブルに保存されている(不一致)
・カラムが多すぎるテーブル
・レコードが多すぎるテーブル
・特定の桁に意味を持たせたコード(上位3桁が商品大分類...)
・怖くて、データベースの設計は変更できない (末期症状?)

一つの入れもの(カラムやテーブル)、なんでもかんでもつっこんでしまう
「詰め込み症候群」ですね。

洗練された設計は、カラムやテーブルがとてもシンプルな目的だけの
ために存在している。

データーベース自体は、情報を集約して管理する仕組みですが、
それと、カラムやテーブルになんでも詰め込むのは別の問題です。

顧客関連の情報を、とにかく CUSTOMER テーブルにカラムを追加して
なんでもかんでも、詰め込むと、何が起きるか?

・SQL 文が複雑になる
・プログラムが複雑になる
・見通しが悪くなる(障害・データ不整合の調査に時間がかかる)
・変更ができない (変更すると何が起きるか、誰も見通せない)

良いことは何もありません。

大原則
「関心の分離」(ひとつの関心に集中)

クラス設計でも、テーブル設計でも、役割が単純で明快なクラス/テーブルを
設計すること。

経済リソースと経済エージェント

商品や顧客を「リソース」系と分類していたが、意思を持って、自律的に活動する
主体は、「経済リソース」から分離して「経済エージェント」としてモデリング
したほうが、良い。

リソースは「モノ」であって管理の対象。
エージェントは「ヒト」であり、意思、判断能力、感情などを持つ。

クラスやテーブルとして「情報」として扱うときも、やはり「モノ」と
「ヒト」とは、扱い方を変えるべき。

人材サービスの分野では、面白い(?)のは、人自身が商品である点。

HR-XML のモデルを使うと、ここらへんは

Candidate ( 商品としての人材 )
Candidate Supplier ( 応募する主体としてのヒト )

になっている。

応募者に関する情報を「商品の記述」と「応募活動をしている個人」に
分離して、クラスやテーブルとして扱うのがよさそう。

設計の大原則「関心の分離」ですね。 商品に対して持つ関心ごとと、
その商品の提供者に対して持つ関心ごとは別です。

気に入った商品を見つけたら、商品の提供者に連絡する、という簡単な
例で考えても、

・商品を見つける
・商品の提供者に連絡する

という明らかに異なる問題領域 ( Domain Context )を扱う。

もちろん、人材という商品を、記述するのは、工業製品を記述するのと
比較にならないくらい、難しいテーマですが。

ビジネスパターンによるモデル駆動設計

評価:
Pavel Hruby
日経BPソフトプレス
¥ 4,935
(2007-08-13)
ビジネスアプリケーションのクラス設計、テーブル設計の参考になります。

ビジネスの基本エンティティを、
R: 経済リソース (商品など)
E: 経済イベント (受注、出荷、請求など)
A: 経済エージェント ( 企業、顧客、従業員など )
の3要素でモデリング、というのが基本コンセプト。

あとは、これらの要素を使った、ビジネスモデルのパターン集です。

基本パターン:12種類
振る舞いパターン:12種類

数は、それほど多くありませんが、精選されていて、説明も具体的で、
わかりやすい。
また、いくつかのパターンは、Java での実装例も示されていて、
現場のモデリングや設計の参考になります。

開発者は、もっとビジネスに重大な関心を持つべし

Domain-Driven Design の著者の Eric Evans が、
InfoQのインタビューで、
Domain-Driven Design の基本は、技術者がもっとビジネスに重大な関心を払うべき、ということをしゃべっていた。

実際の技術者の世界は、技術に関心を持つ人は多いが、自分が開発しているシステムが
どんなビジネスシーンで、どのように使われ、どんなものが期待されているかに、
時間とエネルギーを傾けて取り組んでいる人は、かなりの少数派でしょう。

Domain-Driven Design が難解という評価がでてくる背景として、そもそも、
ビジネスに重大な関心を持たない技術者に、いくらこの本の内容を説明しても、
まあ、馬の耳に念仏、ということなんでしょうかね。

交差表 ?

テーブル設計で、「交差表」という言葉をつかったけど、Google で検索したら、359件という超マイナーな表現だった。

出所は、日本オラクル監修 R.バーカー著の CASE*METHOD 実体と関連 にある 交差エンティティです。

原文では、Intersection Entity。

Oracle システム設計 では、リンクエンティティ 原文では、 Intersect (Link) Entity。

Intersect は、 SQLの集合演算のキーワードとかぶるのがちょっと気になる。

マイナーだけど、個人的には「交差表」は、良い用語だと思います。

人も仕事もデータだけじゃわからん

良い人材かどうかは、会ってみて、話してみて、いっしょに仕事をしてみなきゃわからん。

良い仕事かどうかは、会社を訪問して、面接して、入社して、実際に働いてみないとわからん。

インターネットの転職サービスは、せいぜい、出会いのきっかけづくりになる程度。
現状のサービスは、どのサイトも似たりよったり。
利用者の満足度もけして高くはない。

だからこそ、IT技術者として、ブレークスルーを狙ってみたくなる。

人も仕事もデータだけじゃ、わからん、ということを謙虚に受け止めたうえで、地道な工夫・改良の積み重ねていけば、突破口が見えてくるはず。

Single is best.

simple と single の語源は同じらしい。

たしかに独身(シングル)は、シンプルな生き方で、結婚は複雑な生き方ではある。

複雑になる結婚といっても、カップリング(結合)の度合はいろいろある。

長続きするのは、ルーズカップリング(疎結合)のほう。お互い必要最小限のかかわりだけ持つ。それで、十分満足という関係。

密接に結びついた関係(タイトカップリング)は、関係がぎくしゃくしだすと、修復がきかない。必要以上に、相手に干渉しだすと、ろくなことはない。

クラス設計の基本。

・ひとつひとつのクラスはシンプル(役割をひとつ)にする
・協調して動作するカップルをつくる
・関係は、疎結合にする

二人を一体化するのは、典型的な設計ミス。
個々が独立していて、必要最小限のかかわりあいで結びつくから、軽やかな良い協調(コラボレーション)を実現できる。


Domain-Driven Design を Spring Framework で実践する

Domain Layer と他のレイヤ

Domain-Driven Design (DDD)では、一般的なアーキテクチャとして、次のレイヤ構造を説明している。
・User Interface
・Application Layer
・Domain Layer
・Infrastructure Layer
DDD では Domain Layer のオブジェクトの設計が、ソフトウェア開発の中核であり、開発プロセス全体を駆動するとしている。

では、他のレイヤの設計・開発は、具体的にどうなるのか?

ドメインオブジェクトと永続化

私たちは、永続化フレームワークとして、iBatis を使っている。 iBatis は、オブジェクト/リレーショナルマッピング ( O/R マッピング ) のツールで、SQL 文を XML ファイルに記述する方式。

ドメインオブジェクトの設計とテーブル設計は、ほぼ同時進行。というか、ドメインを分析することは共通。分析結果を Java で表現するか、データベースのテーブルで表現するかという違いなので、基本部分は同じ作業だと思っている。

ドメインオブジェクトとテーブルができてしまえば、iBatis を使った永続化メカニズムの実装はあっけないくらい簡単です。

クラスもテーブルも役割を単純にした設計をしておけば、永続化の SQL 文もシンプルになり、iBatis でのマッピング記述は簡単そのもの。

iBatis と Hibernate

永続化のフレームワークでは、Hibernate を使ったこともあります。Hibernateは、データベースアクセスが自動化され隠蔽されるのが、メリットでもあり、デメリットでもある。

iBatis のほうが、やりたいことを直感的に記述できるし、理解も容易、変更も簡単、というのが私たちの判断です。

ドメインオブジェクトとユーザインタフェース

ドメインオブジェクトとユーザインタフェースのマッピングは、私たちは、Spring MVC を利用しています。

Spring MVC は、View テクノロジーが選択可能です。私たちは、JSP ではなく、テンプレートエンジンの Velocity を使っています。

Spring MVC の Model オブジェクトを View にマッピングするメカニズムは、シンプルでわかりやすい。Modelオブジェクトは、ドメインオブジェクトをそのまま使います。

ユーザの入力内容の取得も、Spring MVC のデータバインドの仕組みを使って、ドメインオブジェクトに直接マッピングしています。 入力検証も Validater インタフェースを持った、ドメインオブジェクトを作って、Spring MVC の構成ファイル ( xml ファイル ) に記述するだけです。

ドメインオブジェクトさえ作れば、あとは、Spring MVC の xml ファイルと、Velocity のテンプレート記述ファイルを用意するだけで、ユーザインタフェース層は完成です。 追加のJava のプログラミングはありません。これこそ Domain-Driven (ドメイン駆動)の開発です。

ドメインオブジェクトとアプリケーション層

Eric Evans の説明では、アプリケーション層のオブジェクトは、業務処理の手順を管理することが役割です。

私たちは、このレイヤの実装に Spring Web Flow ( SWF )を利用しています。

Spring Web Flow は、画面遷移を、xml で記述して実装するフレームワークです。 MVC のC (コントローラ)のプログラミングが不要になります。

画面表示やHTTPリクエストの処理に必要なドメインオブジェクトを xml ファイルに記述するだけです。
ドメインオブジェクトの処理結果によって、別画面に分岐するなども含めた複雑な画面アプリケーションも簡単に実装できます。

ドメインオブジェクトと XML マッピング

Web サービス、REST 系のサービス、外部とのファイルでのデータ交換を実現する時、オブジェクトと XML 文書との双方向のマッピングが必要になります。 O/X マッピングですね。

このマッピングは、正式リリースされたばかりの Spring Web Services フレームワークを試行中です。ドメインオブジェクトの設計すれば、XML とのマッピングの面倒くさいプログラミングが不要になりそうです。

メッセージングサービスや電子メール

メッセージングサービスや電子メールも、Spring Framework を利用すると、低レベルのAPIを使ったプログラミングを簡略化できます。 ドメインオブジェクトが必要な情報持っているので、それを、メッセージとしてキューイングしたり、電子メールで送信する処理が簡単に実現できます。

DDD の実装基盤 Spring Framework

Domain-Driven Design で、開発を実践する場合、Spring Framework を中心に、iBatis, Velocity, Spring Web Flow ( SWF ) , Spring Web Services などをうまく使えば、他のレイヤの開発工数をずいぶんと減らせる。

開発者は、ドメインの分析と設計に集中でき、まさに Domain-Driven の開発になります。

フレームワークを習得して、使いこなすには、それなりの時間とエネルギーが必要ですが、それほど、高いハードルではないでしょう。永続化やユーザインタフェース部分での効果は絶大です。一度、使えるようになると、低レベルのAPIを駆使する開発に戻る気にはなれません。

フレームワークを使いこなすには、Domain-Driven Design をしっかりやって、疎結合で凝集度の高いドメインオブジェクト群をしっかりと用意することです。Spring 系のフレームワークは、そいういう良質の POJO を組み合わせるだけで、しっかりとしたアプリケーションを構築する便利な手段を提供してくれます。

テーブル設計 データモデリングのエッセンス(5)

ビジネスルールとは

業務を進める上で、さまざまな決めごと、約束事があります。

・販売価格
・15:00までの注文は、翌日配送
・7日前までのキャンセルは、キャンセル料を請求しない
・小口の注文は宅配便、大口の注文は、倉庫から直送
・先着100名は、10%の特別割引をする
・和書と雑誌は、ポイントで割引はできない
・洋書はポイントで割引をする
・送料は商品種類にかかわわらずポイントで割引できる

業務アプリケーションでは、このビジネスルールを明確にして、実装することが、重要課題です。ビジネスルールがうまく実装されたシステムは、使いやすく、ビジネスの強力な道具になります。

ビジネスは生き物ですから、ビジネスルールは状況によって、変化します。この変化に短期間で低コストに対応できるシステムほど、ビジネスにとって、価値の高いシステムになります。

今回は、このビジネスルールの実装をデータベース中心で行う方法をとりあげます。
ビジネスアプリケーションの設計の中核です。もっとも楽しい部分です。

ビジネスルールの実装パターン

業務アプリケーションで、これらのルールを実装する方法は、次の三つがあります。

・プログラムのコードで記述( if 文など )
・ルールをDBのテーブルに記述(価格、割引率など)
・テーブルに制約を宣言する ( NOT NULL, 参照制約 )

アンチパターン

ビジネスルールを、力づくで、その場しのぎで if 文を プログラムコードに追加していく。典型的なアンチパターンですね。バグの巣になりやすく、保守性がどんどん悪くなる。

DDD 、リファクタリング、Spring

ドメインオブジェクトをきちんと設計し、個々のビジネスルールを単純に実装した評価メソッド群を作る。ドメイン駆動設計 ( DDD : Domain-Driven Design )の基本思想ですね。また、Fowler のリファクタリングでは、多くのパターンが、ビジネスルールを分かりやすく記述することに関係しています。例えば、第9章「条件記述の単純化」の例が参考になります。

ビジネスルールをプログラムコードに記述する場合、定数などは、Spring の Bean ファクトリの仕組みを使って、XML ファイルに記述すると変更が容易になります。

ルールテーブル

価格や割引率は、テーブルとして実装することが普通に行われます。少し複雑なビジネスルールをテーブルとして設計・実装する例は、後述します。

ビジネスルールをテーブルとして実装すると、変更や内容確認が容易になります。

データベース制約

データベースの制約は、必須ルールや不変ルールの実装方式として最も厳格で安全な手段です。

【一意制約】

主キーをシステムで生成したサロゲート(代理)キーにした場合、商品番号とか顧客番号という自然キーを一意制約を宣言することがあります。

この情報は重複すべきではない、というルールがあれば、積極的に一意制約を宣言して、データベースに問題データを追加できないようにします。

【NOT NULL制約】

ビジネス上 必須の情報は、データベースで NOT NULL 制約を宣言します。
画面やドメインオブジェクトで必須チェックをしていても、データベースでも NOT NULL 制約を宣言すべきです。それぞれの役割と効果が異なるので、3重であっても、それぞれの必須チェックはすべきです。

画面での必須チェックは、ユーザに誤った入力をフィードバックして、その場で修正できる使いやすさの工夫です。

ドメインオブジェクトの必須チェックは、ドメイン(問題領域)の分析結果から、導かれます。ドメインのロジックとして、当然必須チェックをします。

そのオブジェクトをデータベースに永続化する時「データベース側」でも NOT NULL 制約で、整合性のチェックをすべきです。

ドメインオブジェクトには、バグがあるかもしれない。後で保守したときに、バグが混入するかもしれない。画面処理とバッチ処理で、別々のプログラムが、同じテーブルに書き込みをするかもしれない。データの整合性の最後の砦がデータベース側の制約宣言です。

テーブルは役割ごとに分割します。この設計方針だと、ほとんどのカラムは必須つまり NOT NULL 制約の対象です。
NOT NULL 制約が宣言できないカラムを発見したら、そのテーブルは、おそらく、異なる目的が混在しています。目的が単純で明確なテーブルに分割することを検討してください。

【参照制約】

参照制約は、情報の結びつきを宣言してデータの不整合を防止する仕組みです。

受注明細は、受注番号をキーとして、受注ヘッダと結びついています。
出荷レコードも受注番号をキーとして、受注と結びつきます。

テーブルには結びつきを示唆する参照カラムがあるのに、参照整合性制約(外部キー制約)を宣言していないケースが多い。

他のテーブルを参照するカラムは、かならず外部キー制約を宣言します。データの整合性を確保する簡単で確実な手段です。

ビジネスイベント系テーブルで説明したように、先行イベントと後続イベントの関係は参照性制約を一方向に限定して宣言することで、ビジネスの論理モデルをテーブルに実装します。

外部キー制約を宣言すると、INSERT や UPDATE がうまくいかないことがあります。それが正しい姿です。操作がまちがっているか、テーブルの設計がまちがっているかのどちらかです。

ひとつのテーブルで5つ以上も外部キーカラムがある場合は、おそらくテーブル設計の間違いです。役割を単純に、用途を単純に設計すれば、テーブル間の参照関係は、もっとシンプルになります。

ビジネスルールのテーブル設計:価格

ビジネスルールテーブルの典型は、価格表です。何をいくらで売るかは、ビジネスルールそのものですね。

価格は、キャンペーン期間、数量割引、お買い得セット、予約割引などで、同じ商品でも別価格になるのはよくあるケースです。

○○価格が複数あったら、それぞれの価格を別テーブルで設計・実装することを考えます。
標準価格表、キャンペーン価格表、数量割引ルール表、セット価格表、予約割引ルール表など。

KEY を検索すると、VALUE が見つかる LOOKUP テーブルパターンです。

それぞれのテーブルごとに関心を分離して、プログラムもシンプルな構造になります。また、将来、ルールの廃止・追加・変更があった場合にも、副作用を心配せずにテーブルやプログラムの変更ができます。

一つの価格表に多くの属性を持たせると、問題を複雑にして、バグのリスクが増え、保守や拡張がむずかしいシステムになります。

ひとつのテーブルにすべての価格情報をカプセル化したがるのは、典型的なアンチパターンです。入れ物は目的をシンプルにして、小さな入れ物をたくさんつくるべきです。

多くの価格情報をひとつのグループとして管理する方法がスキーマです。関連するテーブルをカプセル化するための仕組みがスキーマです。

ビジネスルールのテーブル設計:送料テーブル

送料は、重量区分と地域区分の組み合わせで決まるというケースがあります。

縦軸に重量区分、横軸に地域区分を並べた、紙ベースの送料早見表がありますね。

こういう表形式のビジネスルールのテーブル設計は、交差表パターンが定石です。

交差表パターンは、三つのテーブルで構成します。

A. 重量区分の一覧
B. 地域区分の一覧
X. 交差表(送料テーブル)

交差表は、重量区分と1対多、地域区分とも1対多の関係で関連づきます。

交差表パターンは、縦横の表形式で記述できるルールをテーブルで表現する応用範囲の広いパターンです。

デシジョンテーブルと呼ばれる、表で縦横の組み合わせごとに○×で表現するルールも、プログラムのif 文でがんばるのではなく、交差表パターンのSQL問合せで実装したほうが、シンプルだし、ルールの変更も容易になります。

状態遷移図であらわせるルールも、2次元の表形式ですから、交差表パターンがテーブル設計の候補です。

ビジネスルールのテーブル設計:デシジョンツリー

デシジョンツリー型のビジネスルールがあります。
質問にYES/NOで答えていくと、最後には、あなたは○○タイプです、というような診断ゲームにでてくるパターンですね。

テーブル設計としては、自己参照テーブルで、実装は可能です。
もし、このタイプのルールが多く、また、そのルールの変更が重要な業務であれば、ビジネスルールエンジンのパッケージやライブラリの利用も選択肢です。

プログラムコードかテーブルか

最初に書いたように、ビジネスルールは、プログラムコードでも実装できるし、テーブル+SQL問合せでも実現できます。

私は、if 文がずらった並んだプログラムは、分かりにくく、保守しにくいと思っています。多くの場合、ビジネスルールは、テーブル+SQL問合せで実装したほうが、シンプルで拡張や変更に強いシステムになります。

もちろん、ビジネスルール記述のテーブルは役割ごとに分割する設計にします。

Domain-Driven Design (DDD) の Responsibility Layers

ビジネスルールテーブルの多くは、Responsibility Layers パターンの Policy Layer のオブジェクトです。業務遂行上の判断や決定をするために必要な情報を提供します。

Policy Layer のテーブルは、下位の Capabilities Layer であるビジネスリソース系のテーブルを参照します。価格表であれば、商品テーブルへの外部キー参照をします。

商品テーブルからは、上位の Policy Layer の 価格テーブルは見えない存在です。

Domain-Driven Design (DDD) の Knowledge Level

送料テーブルで参照する、重量区分テーブル、地域区分テーブルそのものはビジネスルールではありません。ビジネスルールを構成する知識をDBのテーブルで表現したものです。

ビジネスアプリケーションでは、区分テーブルとか分類テーブルがたくさんでてきます。業務の知識や業務上の判断材料として、半ば無意識に利用されている知識を、テーブルで実装したものです。

これらの区分テーブルは、顧客や商品というビジネスリソース ( Capabilities Layer )のテーブルから外部キー参照されます。また、ビジネスルール( Policy Layer ) のテーブルからも外部キー参照されます。

つまり Responsibility Layers パターン では、うまく整理できない種類の情報が、この区分や分類のテーブルです。

これを整理する DDD パターンが、Knowledge Level です。Layer ではないので、依存関係は一方向に限定されません。
Eric Evans が書いているように、Knowledge Level は Responsibility Layers と組み合わせて使って、ビジネスルールやそれに関する知識を、分離して整理するための有用なパターンです。

テーブル設計 データモデリングのエッセンス(4)

ビジネスリソース

今回はビジネスリソース系のテーブル設計、データモデリングがテーマです。

ビジネスリソースとは経営の資源です。ビジネスを進めていく上で、利用可能であり、また必要不可欠な企業の財産です。

例えば、ヒト(顧客、従業員、取引先)、モノ(商品、倉庫、店舗)、カネ(資金、与信枠)、情報(コンテンツ、ノウハウ)などです。

ビジネスリソースを適切に管理し効果的に利用するためのテーブル設計、データモデリングが、ビジネスの成功要因、競争優位の源泉になりえます。

ビジネスイベントとの関係

前回まで説明したビジネスイベントは、これらのビジネスリソースとの関連で、発生し、記録します。
・受注は「顧客」が「商品」を注文したイベント
・出荷は「商品」を「倉庫」から「顧客」に発送したイベント

これらの関係を外部キー参照として設計・実装します。

ビジネスリソースの主キー

ビジネスリソースの管理は経営の重大関心ごとですから、業務上の管理番号(Identifier)があるはずです。
私は、テーブルの主キーは、システムで生成したサロゲート(代理)キーを使います。管理番号が変更されるケースとか同じ管理番号複数のレコードが存在するケースを扱うためです。

一方通行の参照(=レイヤ構造)

ビジネスイベントとビジネスリソースの関係は、Domain-Driven Design (DDD) の Responsibility Layers パターンで取り上げられている Operational Layer と Capabilities Layer と同じ関係です。

レイヤ構造ですから、上位のレイヤは下位のレイヤを参照します。下位のレイヤは、上位のレイヤの存在すら知りません。

上位のビジネスイベントはビジネスリソースを外部キー参照します。下位のビジネスリソースは、上位のビジネスイベントを知りません。外部キー参照は不可です。

集約( Aggregates )

ビジネスリソースは、さまざまな属性情報で表現されます。

顧客は、氏名、連絡方法、届先住所、購買履歴など。
取引先は、社名、部署名、担当者、連絡先(電話番号)など。
商品は、商品名、商品概要、特徴、詳細仕様など。

ビジネスリソースは、Domain-Driven Design (DDD) の基本パターンである Aggregates (集約)を適用することが多い。

一つのテーブルにすべての属性を列挙したテーブル設計を見かけます。しかし、テーブルの役割を単純にして、問題を扱いやすくするために、 Aggregates として設計し、実装すべきです。

顧客テーブルのほかに、氏名テーブル、連絡方法テーブル、届先住所テーブルがある。顧客テーブルが全体を集約するAggretate のルートテーブルという構造です。

氏名テーブル、連絡方法テーブル、届先住所テーブルは、DDD の Value Object です。単なる値のリストであり、重複した内容のレコードが存在することもあります。

氏名レコード、連絡方法レコード、届先住所レコードは、顧客テーブルの主キーを参照する外部キー制約で関連づけます。

Aggregates のモデリング方法として「○○変更」という業務の発生を判断材料にします。

連絡方法変更、届先住所変更はありそうですね。こういう変更業務の単位ごとに別テーブルにして、Aggregates パターンとして集約するテーブル設計が良い。

テーブルの数が増えると、複雑に感じる人もいます。しかし、実際にはそれぞれのテーブルに関心を持つ業務は異なります。テーブルとして関心の分離ができているので、業務ごとの設計・開発・テストが単純になり扱いやすくなります。

その業務の切り分けとテーブル分割の一つの判断材料が「○○変更」業務の有無ということです。

ビジネスリソースの登録

Aggregates パターンのテーブル構成だと、新規作成時にすべての情報を登録することは必須ではありません。

情報が発生した時点、明確になった時点で、順次、適切なテーブルにレコードを追加していけばよい。これも関心の分離の設計原則の適用です。

ビジネスリソース情報の変更

まず、内容の変更の前に「○○変更」業務の発生をビジネスイベントとして記録すべきです。誰が、いつ、なぜ、変更したかをビジネスイベント系の別テーブルに記録する。

情報の変更内容は、該当するテーブルに新規作成します。
例えば、届先住所が変更された場合、新しい届先住所のレコードを追加する。

イベント記録と新情報のレコード追加は、1トランザクションにする。

この結果、変更前と変更後の複数のレコードが存在することになります。
ビジネスリソースを参照する多くの業務は最新の状態だけに関心があります。旧レコードは、物理削除してしまうのが単純でわかりやすい方法です。 DDD の Value Object パターンのテーブル設計への応用です。

論理削除フラグを更新して、参照するときには、いつも、そのフラグを検索条件に含める、というのは、面倒なわりには、間違いが多く、メリットが少ない方法だと思います。

データの信頼性や追跡性を確保するためには、

・削除と追加を1トランザクションにする
・削除時にトリガーで、履歴テーブルに、削除内容を記録しておく

などの手法があります。

物理的に削除せず、追加のみにする方法もあります。
この場合は、どの住所レコードが現在有効であるかを示す、現住所テーブルをトリガーで維持します。導出テーブルですね。現住所テーブルは、ドロップしても、オリジナルの届先住所テーブルから、導出可能です。

変更前の情報も必要?

変更前の情報を、参照する業務ニーズをよく検討してください。ビジネスリソースは、通常の業務(オペレーション)では、現在有効な情報のみで十分です。

もし、変更前の情報も参照する業務があるなら、管理番号を新規に発行して、新しいビジネスリソースとして登録すべきです。それが、管理番号の意味だし、ビジネスリソースの管理の正しいやり方のはずです。

ビジネスリソースの利用停止

ビジネスリソースそのものを削除する(ないことにする)、リソースの管理番号を廃番にすることは、通常のビジネスではありません。多くのビジネスイベントの記録から参照されるので、安易に物理削除はできません。

しかし、今後は、この商品は販売停止、受注は不可にする、ということはよくあるケースですね。

この場合、「販売停止」ビジネスイベントをまず別テーブルに記録することが必須です。

論理的には

(全商品 MINUS 販売停止商品)

で、現在、販売可能な商品を特定できます。

実用上は、トリガーを使って、「現在販売可能な商品」テーブルを自動的に維持する方法があります。商品登録時に、トリガーで追加し、販売停止イベント時に、トリガーで削除する。

「現在販売可能な商品」テーブルは、ビジネスルールのテーブルという性格もあります。ビジネスルール系のテーブルについては、次回で説明します。

calendar
      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< September 2007 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM