ポリモーフィック関連はなぜアンチパターンなのか
アンチパターンとは
アンチパターンとは、ある問題を解決することを意図していながら、別の問題を引き起こす手法のことです。
色々なアンチパターンがありますが、今回はその1つでもある「ポリモーフィック関連」についてまとめてみました。
その他のアンチパターンが気になる方は是非手に取って読んでみると面白いです。
ポリモーフィックとは
Polymorphism ( poly = many, morphe = form) is the ability to treat many different forms of an object as if they were the same.
引用元: IBM Documentation
異なる形のオブジェクトを、共通のものとして統一的に扱える性質のことを指します。
子テーブルの外部キーは「分岐」するため、Commentsテーブルの行はBugsテーブルの行またはFeatureRequestsテーブルの行のいずれかと一致します。図中の曲線は排他的な選択を示しています。つまり、特定のコメントは、1つのバグまたは1つの機能リクエストのいずれかを参照する必要があります。
アンチパターン: 二重目的での外部キーの使用
ポリモーフィック関連をRDBで実装する場合、次のような設計ができます。
comments
- id
- content
- target_type -- 'bug' or 'feature_request'
- target_id
この設計では、target_id は 2つのテーブルのどちらかを指す という「二重目的」の外部キーになります。
しかし、RDBの外部キーは本来 1つのテーブルだけを参照する ことを前提に作られています。
そのため、この設計にはいくつかの問題があります。
外部キー制約が貼れない(整合性が壊れる)
target_id は bugs.id または feature_requests.id のどちらかを指しますが、
RDBは「どちらか一方」を保証する制約を持てません。
型安全性がない
メタデータではなくアプリケーションコードに過度に依存することになってしまいます。
なぜアンチパターンと呼ばれるのか
RDBの本質は、制約によってデータの正しさを保証すること。
しかしポリモーフィック関連では、上記の理由により、RDBを使っているのにNoSQL的な運用に近づいてしまいます。
これがアンチパターンと呼ばれる理由です。
解決策
参照を逆にし、交差テーブルを作成
Comments.target_type列が不要になり、メタデータによってデータの整合性を確保できるようになります。そして、アプリケーションコードに頼ってエラーなく関連付けを管理する必要がなくなります。
共通のスーパーテーブルを作成する
これらのテーブルは、自身で新しい値を生成するのではなく、Issuesテーブルで生成された代理キー値を参照します。特定のコメントを指定すると、比較的簡単なクエリで参照されているバグや機能リクエストを取得できます。
まとめ
ポリモーフィック関連は、アプリケーションコード上では扱いやすい一方で、RDBの制約機構と相性が悪いため、
- 参照整合性が保証できない
- 型安全性がない
- 削除時の整合性が崩れる
といった問題を引き起こします。
そのためRDB設計ではアンチパターンとされることが多いですが、
小規模・低整合性要件・ORM中心設計 の場合には実用上問題にならないケースもあります。
重要なのは、「常にベストプラクティスを適用すること」ではなく、何を作るのか・どの程度の整合性や拡張性が求められるのかを踏まえ、設計を選択することです。
設計には唯一の正解はなく、システムの規模・要件・将来の変化・運用方針など、複数の要因を考慮した上で最適なバランスを取る必要があります。
Discussion