ソフトウェア開発において、データの永続化は避けて通れない課題です。この課題を効率的に解決する設計パターンのひとつが リポジトリ(Repository) です。リポジトリは、データベースやストレージ、インメモリキャッシュなどのデータ永続化層と直接やり取りを行う役割を担います。
リポジトリを導入することで、アプリケーションのドメインロジックをデータ永続化層から切り離し、疎結合を実現します。
そして、しばしば議論になるのが、リポジトリはデータベースのレコード単位で作成するべきか、それともエンティティ単位で作成すべきか という点です。
本記事では、結論として エンティティ単位の設計を推奨 します。その理由を、レコード単位のリポジトリが抱える問題点とともに解説します。
なぜレコード単位のリポジトリでは問題が起きるのか?
結論として、データベースのレコードは単なるデータの塊であり、実際の利用方法を反映していない ためです。実際にデータを利用する際は、適宜結合や選択を行った上で使用する必要があります。
データベースのレコードは単なるデータの塊である
リレーショナルデータベースでは、正規化の程度によってテーブルの数や粒度が異なります。例えば、従業員(Employee)テーブルを考えてみましょう。
▼Before: 正規化されていないテーブル(Employee)
社員ID | 名前 | 部署ID | 部署名 | 役職 | 住所 | 緊急連絡先 |
---|---|---|---|---|---|---|
0001 | サンプル 太郎 | 01 | 総務部 | 部長 | XXX | XXX-XXXX-XXXX |
0002 | サンプル 次郎 | 02 | 営業部 | XXX | XXX-XXXX-XXXX | |
0003 | サンプル 花子 | 01 | 総務部 | XXX | XXX-XXXX-XXXX |
このテーブルには 「部署 ID」 と 「部署名」 の冗長なデータが含まれています。仮に「総務部」の名称を「人事・総務部」に変更する場合、総務部に属するすべての従業員レコードを更新しなければならず、非効率的です。
そこで、正規化 を行い、部署の情報を別テーブルに切り出すのが一般的な対応です。
▼After: 正規化されたテーブル(Employee)
社員ID | 名前 | 部署ID | 役職 | 住所 | 緊急連絡先 |
---|---|---|---|---|---|
0001 | サンプル 太郎 | 01 | 部長 | XXX | XXX-XXXX-XXXX |
0002 | サンプル 次郎 | 02 | XXX | XXX-XXXX-XXXX | |
0003 | サンプル 花子 | 01 | XXX | XXX-XXXX-XXXX |
▼After: 正規化されたテーブル(Department)
部署ID | 部署名 |
---|---|
01 | 総務部 |
02 | 営業部 |
正規化を行わないと、データの整合性が担保されず、「人事・総務部」と「総務部」のようにデータの不整合が発生する可能性があります。
この正規化されたテーブルに対して、それぞれのレコード単位で EmployeeRepository
と DepartmentRepository
を作成するのが レコード単位のリポジトリ です。
レコード単位のリポジトリの問題点
例えば、従業員の組織図を作成する場合、 EmployeeRepository
と DepartmentRepository
それぞれからデータを取得し、手動で結合する必要があります。
問題点:
- アプリケーション側でデータの結合処理が必要になる
- リポジトリがデータベースのテーブル構造に依存してしまう
リポジトリを導入する本来の目的は、データ永続化層とドメインロジックを切り離すこと です。しかし、レコード単位のリポジトリでは、アプリケーション側がデータベースのテーブル構造を意識しなければならない という問題が生じます。
データ永続化層から関心を切り離すためのリポジトリであるはずなのに、テーブル構造を知っていないとデータを適切に扱えない。この点が、レコード単位のリポジトリの大きな問題です。
エンティティ単位のリポジトリが導く理想の設計
前述した課題を解決するために、エンティティ単位のリポジトリを推奨します。
リポジトリは用途ごとに設計するべき
リポジトリを設計する際は、そのデータを取得したい目的・用途を考慮 するべきです。
例えば、従業員データを扱う場合でも、用途によって異なるリポジトリが考えられます。
用途 | リポジトリ名 | 必要なデータ |
---|---|---|
組織図作成 | OrganizationEmployeeRepository | 社員 ID、名前、部署情報、役職 |
給与支払い | SalaryEmployeeRepository | 社員 ID、名前、口座情報、支払い履歴 |
このように、異なる目的ごとに適切なエンティティを設計することで、データベースのテーブル構造を意識せずに済む のです。
OrganizationEmployee と SalaryEmployee を別のエンティティとして用意することで、データベースのレコード構造に依存しない柔軟な設計が可能になります。
まとめ:エンティティ単位の設計を選ぶ理由
- レコード単位のリポジトリでは、アプリケーションがデータベース構造を意識する必要がある
- エンティティ単位のリポジトリを導入することで、ドメインロジックとデータ永続化層を明確に分離できる
- リポジトリはデータの用途に応じて設計するのが望ましい
エンティティ単位の設計を採用することで、より柔軟で保守性の高いアーキテクチャを実現できます。