データ定義から読み取る仕様（前編）

[中編はこちら](http://qiita.com/arai_j/items/564e59d0d66e51a4678f)
[後編はこちら](http://qiita.com/arai_j/items/384f5a7c63ff17a580ec)
#1. はじめに
　プログラマとしてお仕事をする場合何らかのプロジェクトへ途中参加することが多いだろう。特に雇われの身ともなればプロジェクトに最初から参加することなんて稀だと思う。
　さて、プロジェクトに参加したときに最初にやることは対象のシステムがどんなものなのかという概要を知ることだろう。ただ、ふつうのプロジェクトならば最初に概要を説明してくれると思うが、システムの大まかな役割とシステムを構成するモジュールの役割を説明する程度で後はドキュメントを読んでおいてね で終わることも多いのではなかろうか。
　だが概要の説明は大雑把すぎるし、かといってドキュメントは無数にありどれを読んだものか迷ってしまう。え？ 読むドキュメントがないって？ その場合はソースファイルというドキュメントがあるじゃないか！　……それこそ膨大な量になるには違いないが。
　ドキュメントの数も膨大だが、その中身もまた膨大だ。テーブル定義を見てもテーブルは無数にあり、テーブルが持つ属性もまた無数にある。どのテーブルが重要なのか見当もつかない。とりあえず読んでは見るもののそのテーブルが使われてないとか一時保存用だったとかよくあることだ。
　そのため自分の担当する機能に関係がありそうなドキュメントから読んでいくことになる。あちこちドキュメントを見てソースを見て担当機能の概要を把握していく。そうして三ヶ月もすれば自分が担当する機能とそれに関連するモジュールに関しては概要をつかめているはずだ。おめでとう。ドキュメントをあちこち見た成果だ。だが全体としてはどうだろうか。未だ怪しい。そんな状況だったりしないだろうか？
　機能毎に詳細を把握してから全体の概要を把握していく。よくあるシステムの把握方法ではある。だがシステムを知る手段としては逆なのではないだろうか？　全体の概要を知ってから機能毎の詳細を知った方が理解も早くなる。
　ではシステム全体の概要を手っ取り早く知る方法はないだろうか？　そんなことを考えて作ってみたのが本ドキュメントである。

　さて、この文章の趣旨は以下のとおりである。

+ システムの概要を知るには概念モデルを見るのが最適だ
+ E-R図はシステムの仕様を簡潔に表現できるすごい図なのだ
+ E-R図もきちんとメンテナンスしようね！

　そして以下のような方を読者層として想定している。

+ ER図？ そんなもんデータベースからツールで自動生成すればいいじゃないか！と思っている人
+ テーブル定義の説明があれば図なんていらんでしょ　線を引くのも面倒いし と思っている人

　ちなみにER図？ 何それ？ と思ったからはまずはこちら「[ER図](http://itref.fc2web.com/technology/entity_relationship_diagram.html)」を見てみるとよいですよ。ER図における記号の意味を忘れたという方も同様にどうぞ。
 
#2. 設計書から読み取れる仕様とは
　さて、本ドキュメントの題名は「データ定義から読み取る仕様」としている。そのため扱う設計書はテーブル定義書とE-R図になる。これらの設計書からどのようなことを読み取るべきなのだろうか？

##2.1 テーブル定義書とデータ
テーブル定義書のフォーマットは色々あるが、たいてい以下の項目が記述されているはずである。

+ テーブルの定義 : 名前とその説明
+ テーブル属性の定義 : 名前・型・NULL可否・デフォルト値・説明など
+ 主キーの定義
+ 制約の定義 : 外部制約やユニーク制約など
+ インデックスの定義

これらの情報を元に以下のような仕様を読み取っていく。

1. システムが扱うデータの分類方法
2. システムが扱うデータの範囲
3. システムがデータを一意のものと見なすための項目
4. システムがデータを一意のものと見なすための項目で主キーではない項目(テーブルの候補キー)
5. テーブル同士の関連
6. テーブル同士の関連多重度
7. データの形式や値域
8. テーブル中の業務上必要な項目とシステム上必要な項目の区別
9. 主キーの元で唯一定まる従属属性の確認
10. システム上重複がありえる項目の確認
11. データに対するシステムの主要アクセスパターン

上記は以下のようにして読み取る。
1)　システムが扱うデータの分類方法に関してはテーブル名一覧で確認する。一覧が単なる羅列であるならば残念ながら分類方法を読み取ることはできない。

2)　システムが扱うデータの範囲に関しては各テーブルの定義で確認する。テーブル定義にない事項はシステム管理外の情報ということになる。

3)　システムがデータを一意のものと見なすための項目に関しては主キー定義で確認する。

4)　システムがデータを一意のものと見なすための項目で主キーではない項目(テーブルの候補キー)に関してはユニーク制約とNULL可否(不可であること)で確認する。主キーはシステム的な理由(複合キーを避けるなど)でシーケンス番号を代替キーとしていることが多い。そのため候補キーを把握するのは大切なことだ。理由は三章で述べる。

5)　テーブル同士の関連に関しては外部制約で確認する。関連がある・ないはE-R図を見た方が手っ取り早い。だがどの項目が外部キーとなっているのかはテーブル定義で確認する必要がある。

6)　テーブル同士の関連多重度は外部制約のActionで確認する。Action定義自体はテーブル定義書にはないかもしれない。その場合はDDLで確認する。多重度は以下のようにして確認する。
　a) ActionをnoAction/delete on cascadeとしている場合の多重度は1:Nである。
　b) Actionをset NULLとしている場合の多重度は0/1:Nである。

7)　データの形式や値域に関してはテーブル属性定義やテーブル属性説明で確認する。値域に関してはドメイン定義書が別途あると把握が楽で便利だ。

8)　テーブル中の業務上必要な項目とシステム上必要な項目の区別に関しては属性のNULL可否とテーブル属性定義説明で確認する。業務上必要となる項目は本来NULLにはならないはずである。

9)　主キーの元で唯一定まる従属属性の確認に関してはテーブル属性定義で確認する。主キー以外の属性が従属属性である。なぜこのことを確認するのかというと、その主キーのもとでは従属属性は一つ以外の値を取れないという制約も確認できるからだ。
　例で示す。
 　例) 　社員テーブル 主キー：社員番号 従属属性：所属部署　とシステム上で定義されているとする
　　　社員が所属する部署はこの場合一つのみとなる。
　　　もし社員が複数の部署に所属する場合このシステム上では複数の社員番号をその社員は持つことになる。

10)　システム上重複がありえる項目の確認に関してはユニーク制約の有無で確認する。項目が主キーである場合は当然ユニーク制約が有である。これも例で示す。
社員テーブルがあるとする。
　a) 主キーを名前としている場合そのシステム上では同姓同名を許さないということになる。
　b) 主キーを社員番号としている場合そのシステム上では同姓同名も許容するということになる。なぜならば社員番号が異なっていればよいからだ。

11)　データに対するシステムの主要アクセスパターンに関してはインデックス定義で確認する。インデックスがあるということはその組み合わせのアクセスが多い証拠でもある。テーブル定義書内にインデックス定義がない場合はDDLなどデータベース定義で直接確認する。

　このようにテーブル定義書からはシステムの概要から詳細まで実に多くの仕様を読み取れる。だが、その分記載されている情報も膨大になる。ゆえにテーブル定義書から概要を把握するのは難しい。

##2.2 E-R図
E-R図には以下の情報が記載されている。

+ エンティティ名
+ エンティティの性質（依存か非依存か）
+ エンティティ間の関連
+ 関連の多重度
+ 主キー
+ 外部キー
+ 代理キー
+ エンティティの属性
+ スーパタイプとサブタイプ

　少し補足する。
　エンティティの依存・非依存のことだがほかのエンティティが無いと存在できないエンティティを依存エンティティと呼び、ほかのエンティティが無くても存在できるエンティティを非依存エンティティと呼ぶ。

　代理キーのことだが本来存在する主キーの代わりに実装上の都合から追加したキーをそう呼ぶ。たとえば複合主キーの変わりに主キーとして定義したシーケンス番号が代理キーである。

　スーパタイプとサブタイプのことだがいわゆる親子関係のことである。親はエンティティの共通的な性質を持ち、子がその親の性質を受け継ぐ。スーパタイプが親であり、サブタイプが子である。
　なお、サブタイプの種類としては
　　a) 排他的（OR）：　常に一つのサブタイプのみに属する
　　b) 包括的（AND）： 複数のサブタイプに属する
　というものがある。
　排他的の例）「契約」は「書面」か「オンライン」のどちらかである
　包括的の例）「社員」は「運用者担当者」でもあり「サポート担当者」でもある
　※E-R図の記法であるIDEF1X記法には他にも確定的・未確定的というサブタイプの種類があるがここでは割愛する。
　実際にテーブルを定義するときにはスーパタイプとサブタイプを統合して一つのテーブルとすることが多い。 統合したテーブルはある項目が特定の値を取る時のみ設定されるような項目を持つ（要するにNULL可の項目となる）。

　また、E-R図には表現のレベルがあり、それぞれ概念モデル・論理モデル・物理モデルがある。
　概念モデルは名前のとおりシステムが持つ本質的なエンティティの関係を記載したモデルである。
　論理モデルは概念モデルを詳細化したもので、物理モデルは論理モデルを実際のテーブルへ展開するために作成するものである。
　テーブルを定義するRDBMSに論理モデルは依存しないが物理モデルは依存する。このため、論理モデルから物理モデルを作成するときに実装上の都合で変更したりする。代理キーの作成やスーパタイプとサブタイプの統合がその作業に相当する。
　上記にE-R図に記載される情報を示したが、モデル毎に記載される範囲は異なる。
　概念モデルでは、エンティティ名・エンティティの性質・エンティティ間の関連・関連の多重度を記載する。
　論理モデルでは、エンティティ名からスーパタイプ・サブタイプまですべてを記載する。
　物理モデルでは、スーパタイプ・サブタイプ以外のすべてを記載する。

　これらの記載情報を元に以下のようなシステムの仕様を読み取っていく。

1. 業務上重要なデータ群
2. 本来の主キー
3. エンティティの性質を表す重要な属性
4. システム系テーブルの区別
5. データが成立するための事前条件
6. データ間に存在する依存関係の条件
7. データ間に存在する依存関係の意味
8. エンティティが持つ種類
9. 特定の条件にのみ成立する関連
10. エンティティ内の制約条件

上記は以下のようにして読み取る。
1)　業務上重要なデータ群に関しては概念モデルのエンティティ定義で確認する。概念モデルで登場するエンティティは業務上必要なものだからである。

2)　本来の主キーに関しては論理モデルのエンティティ定義で確認する。2.1のテーブル定義では主キーは代替キーとなっていることが多いと述べた。一方論理モデル上では代替キーとなっていないのでそれで確認できる。

3)　エンティティの性質を表す重要な属性に関しては論理モデルのエンティティ定義で確認する。E-R図上に属性すべてを記述するのは現実的ではないためある程度絞っている。逆にいえば記載されているのはそのエンティティの主要な属性ということになる。

4)　システム系テーブルの区別に関しては概念モデルと論理モデルの差分で確認する。概念モデルにあるエンティティが業務上必要なものである。そのため論理モデルで増えたエンティティを見ればシステム系テーブルかどうかは調べやすい。

5)　データが成立するための事前条件に関してはエンティティにおける依存・非依存の性質で確認する。
　　　a) ◯◯はXXがない場合は存在しない（◯◯がXXに依存する場合）
　　　b) △△はXXがなくても存在する（△△がXXに依存しない場合）
　　ということが依存・非依存の関係からわかる。

6)　データ間に存在する依存関係の条件に関しては関連の多重度で確認する。
　あるエンティティAとB間に存在する関連の多重度をm:nとする。
　m=1:nである場合AとBの条件は以下のようになる。
　Aの条件）　
　　Bのレコードに対応するAのレコードが必ず一意に定まる
　Bの条件）　
　　B中にはAに対応しないレコードが存在しない。ということはAがないとBは作れないことになる。
　　N>=1である場合、Aに存在するレコードに対応するレコードがB中には必ず存在する。
　　N>=0である場合、Aに存在するレコードに対応するレコードがB中には存在しないこともあり得る。

　一方m=0 or 1:nである場合AとBの条件は以下のようになる。
　Aの条件）
　　Bのレコードに対応するAのレコードが一意に定まる。だが対応するAのレコードが存在しないこともあり得る。
　Bの条件
　　B中にはAに対応しないレコードが存在することもある(NULLなど) 。ということはAがなくてもBは作れることになる。
　　N>=1の場合とN>=0である場合との条件は1:nの時と同様である。
　
　m:nとなる場合、お互いのレコードに対応するレコードがそれぞれ複数存在することになる。なお物理モデルでは最終的にこれが無くなるようにモデルを作成していく。

7)　データ間に存在する依存関係の意味に関しては関連に付けられた名称で判断する。なお、エンティティ＝名詞・属性＝形容詞・修飾子・関連＝動詞とすることで文章を組み立てるとシステムが扱う業務形態を表せる。
　例）社員(社員番号、名前)、部署（部署名、フロア名） 社員-関連：所属する-部署 多重度はN:N
　　　｛社員番号xxxで名前がyyyyである｝社員は{部署名:zzzで所属フロアがyyyである}部署に所属する

8)　エンティティが持つ種類に関してはサブタイプの種類で確認する。

9)　特定の条件にのみ成立する関連に関してはサブタイプが関連を持つかどうかを確認する。ビジネス上の制限となる関連なので重要だ。

10)　エンティティ内の制約条件に関してはE-R図上のエンティティ定義で主キーと従属属性を確認する。エンティティ内の制約条件とは主キーの元に従属属性が成立する値は一つだけということである。また主キー以外の項目は重複があり得ることも確認できる。これはE-R図を見なくてもテーブル定義書で確認できる。だがE-R図上では主キーは本来のものなのでE-R図で確認した方が誤解をしづらい。
　　
##2.3 実データ
実データからも以下のような仕様は読み取れる。

+ システムが扱うデータの種類
+ 特定ロジックの判断基準

システムが扱うデータの種類に関しては
　a) データの定義がある → 扱う対象である
　b) データの定義がない →　扱わない
というようにして読み取る。
特定ロジックの判断基準に関しては
　a) このテーブルレコードの組み合わせは有効と判断する　→　許容リストなど
　b) このテーブルレコードの組み合わせは無効と判断する　→　NGリストなど
として読み取る。
ただしデータなので環境毎に差異があるかもしれない。あくまでも仕様の補足事項として確認する内容ではある。

##2.4 まとめ
　テーブル定義書やE-R図は機能設計書に比べると文章は少なく定義の羅列が多いため読んでいて退屈でありわかりづらいかもしれない。だがこれらのドキュメントから読み取れる内容は上記で示したように膨大なものである。特にE-R図の内容をすべて文章化したらそれだけで分厚い設計書と化すことだろう。
　データはシステムの根幹をなすべきものである。故に概要を把握するためにはまずはデータのことを把握するべきなのだ。そして膨大な仕様を簡潔に記した図であるE-R図を見るのが最適なのである。
#3. 設計書が欠けると落ちていく仕様
 理想は、すべてのレベルのE-R図（概念モデル・論理モデル・物理モデル）が揃っていることである。ではこれらが欠けているとどうなるのだろうか。
##3.1 テーブル定義はあるがE-R図（物理モデル）がない・自動生成のみの場合
以下のような不都合が生じる。

+ 候補キーを確認できない
+ 関連を失う
+ 関連の意味がわからない
+ サブタイプを失う
+ 正確な多重度がわからない

次にこれらの原因と問題点を示す。
**候補キーを確認できない**
　原因）　
　　本来の主キー（複合主キー）は代理キーとなることが多く、本来の主キーにユニーク制約を付けていないとそれが主キーだとわからない。
　問題点）
　　・エンティティが本来何のキーを元に唯一となるのかがわからなくなる
　　・各項目に関して本来重複があり得ないのか・あり得ないのかがわからなくなる

**関連を失う**
　原因）
　　性能面の考慮や実装上の理由により外部キー制約をつけないことがある
　問題点）
　　・本来存在する関連を確認できない
　　・データの整合性をプログラムで保つ必要があるが、どう保っているのかをテーブル定義やE-R図からは読み取れない

**関連の意味がわからない**
　原因）
　　DDLでは関連の名称を定義できない。そのため自動生成では抽出不可能となる。
　問題点）
　　業務形態を示せなくなる

**サブタイプを失う**
　原因）
　　一般的なデータベースではサブタイプ自体を定義できない
　問題点）
　　・スーパタイプ・サブタイプを統合して作成したテーブルの場合NULL可能項目がどんな条件のときに設定されるのかがわからない[^1]
　　・条件付き関連（サブタイプのみが持つ関連）の定義ができないため本来の関連が持つ意味を失い誤解の元となる

**正確な多重度がわからない**
　原因）
　　多重度の個数がデータベース上では定義できない
　問題点）
　　・多重度に明確に上限個数が存在しても、それがわからない
　　・1:NのN>=0なのかN>=1なのかを区別できない。そのため必ずあるのか・無いこともあり得るのかがわからない
##3.2 E-R図（物理モデル）はあるがE-R図（論理モデル）がない場合
以下のような不都合が生じる。

+ サブタイプを失う
+ サブタイプが持つ関連を失う
+ 本来の主キーを失う

次にこれらの原因と問題点を示す。
**サブタイプを失う**
　原因）
　　・サブタイプを実際のテーブルに展開した場合サブタイプを直接表現する方法がない
　　・サブタイプを含むエンティティは通常スーパタイプと統合されたテーブルとして実装される
　問題点）
　　・統合したエンティティに特定のエンティティのみに必要な属性が含まれることになる
　　・エンティティに本来必要な属性・不必要な属性が混在して区別がつかない
　　・サブタイプ固有の属性はNULL可の項目となるが設定条件はモデルからはわからない

**サブタイプが持つ関連を失う**
　原因）
　　サブタイプとスーパタイプを統合したときサブタイプのみが持つ関連を失う
　問題点）
　　統合テーブルでも関連は設定可能だが、本来の意味は失ってしまう

**本来の主キーを失う**
　原因）
　　・複合主キーは通常代理キーを設定する
　　・候補キーとして本来の主キーを定義しなかったときに失う
  問題点）
　　・本来の主キーの項目で複数値がありえるのかありえないのかが区別できなくなる
　　・代理キーさえ異なれば後の項目はまったく同一であるようなレコードが生成可能となってしまうが、モデル上からはそれがあり得るのか・あり得ないのかが判断できない

##3.3 概念モデルがない
　表記レベル上は概念モデルよりも論理モデルの方が上なので抜け落ちる仕様はないように思われる。
　だが概念モデルがない場合「モデルの概要」が抜け落ちる。システムで扱う本質的なエンティティとそれ以外のエンティティとの区別が付かなくなるため全体を手早く把握する術がなくなってしまう。
　ただし概念モデルがあればいいというものでもない。概念モデルと論理モデルの対応付けがされていないとむしろ把握が困難になるからだ。

##3.4 まとめ
　E-R図がないために様々な仕様が落ちていくことを上記で示してきた。もちろん抜け落ちた仕様は何らかのドキュメントで残っているはずではある（最終的にはソースという形で）。 だがそれらの記述は分散していることだろう。故にメンテナンスも大変になる。
　一方E-R図があればそれだけを見ればいいし修正も集中的に行える。さてE-R図があるのとないのとではどちらの状況がバグを生みやすいのだろうか。

[^1]: NULL可能項目は、項目の設定は任意・ある特定の条件の場合は設定されるが条件に一致しないときは決して設定されない・ 設定されるタイミングが異なるというように満たす条件が異なるため区別がつきにくい