IDがあっても、event からコードを削除してはいけない
盛り下がってきたけど、今かすかにID論が熱い!
渡辺氏がIDについて懸念していることに自分もよく引っかかるので、自戒のメモ。
コードはfactだから削除しちゃダメ
ウチで持っているECサイトのパッケージでは、受注明細テーブルに、商品マスタから商品名をコピーして保持している。
商品名は時々変わるので、何かの方法で「販売時点の商品名」が取れるようになっていないと、お客さんに送った納品書と、
システムの受注履歴表示画面とで、商品名が違ってしまうから。
「コードは不安定で外部キーにはなり得ない」という立場に立つなら、コードも名前と同じ意味で、resource から event にコピーする必要がある。
商品コードを外部キーにするトラディショナルな設計では、商品コードは
- 商品マスタの当該レコードを指すポインタ
- 受注というイベントに属するfact(商品名とかと同じ)
の2つの意味を持っている。
ID導入によりポインタとしての意味は剥奪されるが、factであることは変わらない。
受注時点の商品コードを納品書に印字しているなら、システムも受注時点の商品コードを把握していないとまずい。
まあ、そのぐらいいいよというお客さんもいると思うけど。要件によってはまずい。
他の例
- ネジの在庫を、部品コード順に、倉庫内の棚に並べている。
- 部品コード A-100 のネジは、在庫が100個ある。
- このネジの部品コードが何かの事情で X-Y-999 に変わることが決定した。
この時、入庫伝票明細テーブルに部品コードをコピーしていないシステムは、以下のように動くだろう。
- 部品コードは外部キー参照されていないから、部品マスタを1行更新するだけで洗い替え終了。
- 在庫検索機能に新部品コード X-Y-999 を入力すると、100個、と表示される。
- 在庫検索機能に旧部品コード A-100 を入力すると、ありません、と表示される。
さて、これでいいのかどうか。
「部品コード A-100 が入庫された」というfactを記録していない情報システムを持っていると、システム上のコードの洗い替えの瞬間に、
倉庫に行ってネジの現物を「A-100」の位置から「X-Y-999」の位置に移動しなくてはならない。でないと、システムと現実世界とが一致しない。
入庫伝票明細テーブルに部品コードがコピーしてあれば、新コードの在庫が0個で、旧コードの在庫が100個、と表示できる(そうしないこともできる)。
どっちの表示が正しいのかは、現実の業務が決める。
「過去のマスタ」の情報をどこから持ってくるか
ある受注明細について「受注時点の商品コード」を入手するやり方は2つある。
- 受注明細にコピーする
- 商品マスタを履歴管理して、受注明細は履歴データを外部キー参照する
私は1.の方法しか取ったことがないが、この方法は「テーブルをクラスにマップする」指向のO/Rマッパーとあんまり相性が良くない。
オブジェクトモデリングした結果と、O/Rマッパーが生成するオブジェクトグラフが大きく乖離するから*1。
私がドメインモデリングを放棄している理由の一つ。
2.のアプローチの方が、OO派の人に喜んでもらえるオブジェクトグラフを、O/Rマッパーが生成しやすいだろう。
だがこの構成を実装するには、DB観を転回を求められそう。
「resource なんてない。ID以外の全ての属性は event に帰属するのだ!」みたいな。
クラステクノロジーのECObjectsが、多分こういう考え方になっている。「マスタはviewに過ぎない。実表はトランザクションデータのみ」なのだそうです。動くのかそれ?
参考:
E.F.Codd の遺産−ECObjectsのDB設計ウラ話
http://www.class.co.jp/column/backnm07.html
*1:いや、よく知らないんだけど、受注のオブジェクトモデルて、受注明細オブジェクトが商品オブジェクトへの参照を握っている形でたいてい描いてありますよね。そういう形にしにくい