« Redmineのバージョン設定でプロジェクトの設定方法が違う | トップページ | アーキテクチャ設計はベストプラクティスを参照するプロセスに過ぎないのか?~Software Processes are Software, Too(ソフトウェアプロセスもまたソフトウェアである) »

2024/08/31

「システム開発・刷新のためのデータモデル大全」を読み直した感想~親子頻出アンチパターンは初心者モデラーに多い

システム開発・刷新のためのデータモデル大全」を読み直した。
今までの経験を思い出しながら読み直すと気づきが多かった。
気づきをラフなメモ。

【参考】
業務ロジックをデータモデリングはどこまで表現できるか?: プログラマの思索

【1】テーブルをリソース系とイベント系の2種類に分けてみた

データモデリングが重要と分かっていても、ER図を書いてみても実際の業務フローや画面UIがイメージしにくい。
データ構造から業務フローがイメージできないと、単にデータがそうなっているだけとしか分からない。

そこで、マスタであるリソース系はR、トランザクションであるイベント系にはEをテーブルに付けて区別して見るようにしてみた。
業務フローをイメージするために、イベント系のテーブルは、TA字型ER手法を使って、外部キーがある関係は、先行後続を付けて見るようにした。
この考え方は「システム開発・刷新のためのデータモデル大全」にないがあえてやってみた。

業務ロジックをデータモデリングはどこまで表現できるか?: プログラマの思索

(前略)
* resourceとresourceをつなぐ場合:対照表を生成する。対照表はeventである。
 (例)従業員と営業所
     従業員-営業所の対照表を作成し、リレーションシップを保全する。
* resourceとeventをつなぐ場合:event側に参照キーを持たせる。
 (例)顧客と注文
     注文entityに顧客コードを持たせる。
* eventとeventをつなぐ場合
** 「1:1」「1:m」:時系列の遅い方に持たせる。
 (例)受注と請求(一つの受注に対し請求は一つ)
     請求に受注番号を持たせる。
** 「m:1」「m:m」:対応表を生成する。
 (例)受注と請求(複数の受注に対し請求は一つ)
     受注-請求の対応表を生成し、リレーションシップを保全する。
(後略)

その結果、イベントに先行後続が順序付けられて、業務フローが見えてきて、付随するリソース系のイメージも湧いてきた。
そこから色々感じたこと、気になったことをメモしておく。

【2】リソース系テーブルのフィーチャオプションモデル

システム開発・刷新のためのデータモデル大全」では、製造業のモデルだけでなく、サービスやその他のモデルでもリソース系テーブルのフィーチャオプションモデルがよく出てくる。
なぜ頻出されるのか?

たとえば、製品や商品の属性をテーブルで保持しようとすると、横持ちでカラムが多くなる。
サイズ、色、重量などいろんな属性があるし、新製品によってさらに属性も新規追加されやすい。
横持ちのテーブルでは品種が多くなると破綻する。
そこで、品種という属性群を別テーブルで保持し、縦持ちでデータを持たせて、新規追加できるようにする。
つまり、製品や商品の属性データを横持ちから縦持ちにもたせて、汎用化している。
その分、マスタテーブル設計は複雑になるが、理解さえできれば応用が効きやすい。

フィーチャオプションはマスタ管理を整理するためのテクニックと思う。

【3】強属性のキーはサロゲートキーの代わり

複合主キーのマスタは、サロゲートキーにすると扱いやすくなる。
しかし、関数従属性がサロゲートキーのために分かりにくくなる。
そこで、サロゲートキーに置き換えられた複合主キーに当たるカラムを一度追加更新されたら更新できない制約をかける。
システム開発・刷新のためのデータモデル大全」では、この制約を強属性と呼んでいた。
複雑な商品マスタをサロゲートキーで主キーにした時、品種区分とFO項番が主キーのようになるが、「システム開発・刷新のためのデータモデル大全」の例では、品種区分を強属性としている。

強属性を使うことでマスタテーブルの関数従属性を表し、データの不整合が出ない仕組みにしている。


【4】親子頻出アンチパターン

データモデリング初心者はテーブル同士を関連付けようとする時、主キーの親子関係だけで表現しようとする。
特にトランザクション系のテーブルで多い。
注文と注文明細みたいに。
たぶんそういう関係付けの方がイメージしやすいからだろう。
そういうアンチパターンは、親子頻出アンチパターンと言われている。

しかし、本来は外部キーを使って、トランザクション系のテーブルに先行後続を関連付けるべきだ。
その場合、先行後続では多重度が異なる。

先行後続が1対多ならば、先行イベントテーブルの主キーが後続イベントテーブルの外部キーとして設定される。
一方、先行後続が多対1や多対多ならば、先行イベントテーブルと後続イベントテーブルの間に、連関テーブルが入り込んで2つのテーブルを1対多で関連付ける。
たとえば、出荷したデータをまとめて一括請求する場合などがあげられるだろう。

データモデルではイベント系テーブルを抽出した後、多重度から先行後続を読み取り、そこから業務フローを組み立てると一連の流れが見えてくると思う。

【5】時限NULL、永続NULLデータの考え方

イベント系テーブルでは、カラムの初期値はNULLだが、後続の業務が実行されてデータが更新されるタイミングで、NULLから値がセットされる。
システム開発・刷新のためのデータモデル大全」では、このようなデータを時限NULLデータと呼んでいる。
たとえば、後続イベントテーブルにある先行イベントテーブルの主キーを外部キーとして張っている場合がそうだろう。

データモデルではNULL値はできるだけ避けるべきだが、一時的にNULLの状態であって、データ更新のタイミングで値が更新されるならそれで良しという考え方になる。
システム開発・刷新のためのデータモデル大全」では、発注と入荷のデータモデルで入荷コードが時限NULLとして使われる例があって分かりやすい。

一方、マスタテーブルでは一つのマスタに属性を増やしていくと、カラムの初期値がNULLのまま永遠にセットされる場合がある。
このような例が永続NULLデータになる。
システム開発・刷新のためのデータモデル大全」では、永続NULLデータが存在する場合、サブタイプに分割すると良い。
つまり、テーブルの継承関係を使って、親テーブルのマスタに共通するカラムをまとめ、子テーブルのマスタにそれぞれの属性を集めたデータをまとめる。
顧客や取引先、仕入先などをまとめたテーブルを作りたい場合が相当するだろう。

【6】2次キー(2次識別子)の使い道

システム開発・刷新のためのデータモデル大全」では、2次キーが有効に使われるデータモデリングの例が多い。

たとえば、在庫推移監視モデルでは、受払テーブルが受払予定テーブルと受払履歴テーブルをサブタイプに持たせるが、それぞれの主キーは異なるので、そのままでは継承関係をデータモデルで表現できない。
そこで、受払・受払予定、受払履歴テーブルに2次キーを持たせて、継承関係を表現する。
2次キーはいわゆるAlternative Keyであり、一意なキーだから、検索時にも使える。

他にも、売上履歴に出荷明細、回収明細、一般取引明細の各テーブルを関連付けて、売上の履歴を一元的に管理していつでも検索できるようにするには、それぞれの主キーは異なるので、2次キーを持たせる。

一般に2次キーは、JANコードやマイナンバーのようにマスタテーブルでよく出るが、トランザクションテーブルに使うと効果的に扱える場合が割とあるように思える。

【7】負荷計画のモデルは2種類ある

システム開発・刷新のためのデータモデル大全」では、業務知識を埋め込んだデータモデルがふんだんに盛り込まれているので、データモデルを読み解いていくと、この関数従属性にはこういう業務ルールを埋め込んでいたのか、と気づく時が多い。
宝物探しの感覚に似ている。

システム開発・刷新のためのデータモデル大全」にあるデータモデルで興味深かった例は、負荷計画のモデルだ。
製造業では、工場の機械がリソース制約になり、工場の稼働率を決めて最終的には原価につながる。
そこで、設備の制約に関するスケジューリング決定について、TOCのアイデアを入れて、工程の日程を決める。

負荷計画を立てるときに、リソースの制約がスケジューリングに最も関わるので、制約になるリソースは何があるか、という問いに置き換えられる。
制約になるリソースは、製造業の工場なら設備だが、病院の看護スケジュールなら、専門技術を持つ人員になる。
ソフトウェア開発のスケジュールでも、インフラ環境の設備もあるだろうが、専門技術を持つ開発者が最も大きな制約になるだろう。
つまり、要員シフト管理では、専門技術を持つ人員が制約になる。
制約となるリソースが業態やビジネスによって大きく異なる点が面白い。

また、負荷計画では受注生産の工場、病院の看護師なら、受注済みの製品または予約済みの患者という需要に対し、「需要を設備の稼働を確保する」考え方になる。
一方、航空機運輸業の予約搭乗管理では、飛行機を既に持っており、その飛行機の座席をいかに予約で埋めていくか、になる。
つまり、「設備の稼働ありきで需要を確保する」ことになる。
他にも、新幹線や特急の予約もこの考え方になるだろう。

では、データモデルにはどのような違いが出てくるのか。
受注生産の工場、病院の看護師の負荷計画では、予定→製造指示のようにイベントテーブルは1対多の関係になる。
「需要を設備の稼働を確保する」データモデルでは、需要という予定をいかに設備で捌くか、という考え方になるので、予定→負荷を割り当てた計画スケジュールのように、先行後続のイベントテーブルが1対多になる場合が多い。

一方、飛行機のフライト管理では、フライト日程→フライト日程明細--予約搭乗明細→予約搭乗というイベント系テーブルで関連付けたデータモデルになっている。
つまり、先行後続のイベントテーブルが多対多の関係になっている
「フライト日程明細--予約搭乗明細」の関係は、それぞれの主キーが異なるのでそのままでは関連付けられないが、フライト日程明細テーブルの主キーを2次キーとして予約搭乗明細テーブルに持たせて、関連付けるモデルにしている。
これにより、フライト日程を決めたら、フライト日程の飛行機の座席に予約を割り当てて管理するという業務フローが成り立つことになる。

さらに、フライト日程明細テーブルの主キーを予約搭乗明細テーブルの2次キーに設定しているので、2次キーはNULLも設定できる。
NULLが設定される例として、座席指定できていないデータ、キャンセル待ちや搭乗者にカウントされない乳幼児があげられていて、そこまで業務ルールとして埋め込んでいるのか、と気付いて面白かった。

他のデータモデルでも、関数従属性に業務ルールが巧妙に埋め込まれているので、この辺りを読み解くと面白いと思う。

|

« Redmineのバージョン設定でプロジェクトの設定方法が違う | トップページ | アーキテクチャ設計はベストプラクティスを参照するプロセスに過ぎないのか?~Software Processes are Software, Too(ソフトウェアプロセスもまたソフトウェアである) »

IT本」カテゴリの記事

モデリング」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« Redmineのバージョン設定でプロジェクトの設定方法が違う | トップページ | アーキテクチャ設計はベストプラクティスを参照するプロセスに過ぎないのか?~Software Processes are Software, Too(ソフトウェアプロセスもまたソフトウェアである) »