なんか良さそうだなと思って ORM を使い始めてから数年が立ちますが、ずっと使いづらいなと思いながら使っていました。ただ、最近色々なことを調べているうちに、そもそも使いどころが間違っていたという事に気が付いたのでまとめてみます。
使いづらいとは
私はとりあえず手を動かすタイプなので、概念とか基礎の勉強は後回しになりがちです。そういった学習方法を取る中で、
- 世の中の一定の人が絶賛しているツールがある
- しかし自分は使いづらいと思う
というときは、大抵使い方を誤っている時に発生すると思っています。ツールを作った人の考えを理解せず、自分の考えに無理やりはめ込もうとしているのです。ということで、まずは基礎から見直してみることにしました。
ORM とは
ORM について Wikipedia から引用してみます。
オブジェクト関係マッピング(英: Object-relational mapping、O/RM、ORM)とは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である。オブジェクト関連マッピングとも呼ぶ。実際には、オブジェクト指向言語から使える「仮想」オブジェクトデータベースを構築する手法である。
オブジェクト関係マッピング – Wikipedia
ここで出てくるデータベースとはリレーショナルデータベース(RDB)のことです。
オブジェクトを表に
リレーショナルデータベースは表形式でデータを保持します。対して、オブジェクトは単純な表形式のような構造にすることもできますが、通常は複雑な構造をします。たとえば以下のようにプロパティの中身がオブジェクトになっており、入れ子のような構造になっている場合です。
// 従業員オブジェクト
{
"従業員ID": 1,
"名前": "田中太郎",
// 従業員テーブルと部署テーブルに分かれそう
"所属部署": {
"部署ID": 20,
"名前": "部署名",
"所属従業員": [
// 循環参照
{
"従業員ID": 1,
"名前": "田中太郎",
// ...
},
// ...
],
},
// テーブル分けるほどの内容か・・・?
"保有スキル": [
"Java",
"Hibernate",
],
}
従業員ID | 名前 | 所属部署 | 保有スキル |
---|---|---|---|
1 | 田中太郎 | ? | ? |
オブジェクトをどうやってデータベースに格納するか、という問題を解決する方法としてデータマッパーという考え方があり、それを実現したものが ORM という位置づけです。
「オブジェクトを保存する」ものである
ORM は使いづらいと思っていた原因なのですが、ずっとリレーショナルデータベースを意識していた点に問題がありました。テーブル定義を先に考えて ORM を使おうとしていたのです。上記の通り、ORMは「「仮想」オブジェクトデータベースを構築」1オブジェクト関係マッピング – Wikipediaする、つまりオブジェクトを保存する(永続化という)ための仕組みであり、リレーショナルデータベースからデータを読み込むことを主な目的とした物ではないのです。データベースのデータではなく、オブジェクトが主軸なので、オブジェクトの設計が重要になります。
ドメインモデル
ORM製品はいくつかありますが、そのうちの1つである Hibernate を使っている時に Hibernate のドキュメントを頭から読んだことがあります。このドキュメントはかなり書き込まれていて、章立てだけ見ても34章まであるという立派なものです。このうちの第2章には「ドメインモデル」という概念について記載されています。Hibernate を説明する文書の2番目に来ることから、かなり重要で先に理解すべきことであることが伝わってきます。
そのドメインモデルの章に Wikipedia への参照があり、そこでは下記の2種類の本が引用されています。
- Fowler, Martin. Patterns of Enterprise Application Architecture. Addison Wesley, 2003, (邦題:エンタープライズアプリケーションアーキテクチャパターン 翔泳社)
- Evans, Eric Domain-Driven Design: Definitions and Pattern Summaries. Domain Language Inc., 2006, (邦題:エリック・エヴァンスのドメイン駆動設計 翔泳社)
知らなかったのですが、前者は 「PofEAA」, 後者は「DDD」や 「Evans 本」と呼ばれ、かなり有名なようです。
上記の2冊を読んでみたところ、 PofEAA には業務アプリケーションを作る際のよくある設計パターンが記載されており、そのうちの1つとしてドメインモデルやデータマッパーが紹介されています。他に ORM や DDD で使われている概念についても記載されています。
Evans 本にはドメインモデルの設計手法について記載されています。こちらには業務システムのユーザーが実際の業務で使う言葉が、そのままプログラマーが作るオブジェクト(クラス)の名前として存在すべきだよね(ユビキタス言語)というところから、ドメインモデルをどうやってソフトウェア上で表現するかというところまで、ドメインモデル設計について幅広く書かれています。(この紹介文はざっくりまとめたものなので、正確性は乏しいです。本を読んでみることをおすすめします。)
ドメインモデルの詳細については紹介しきれないのでこのくらいにします。ここで言いたいのは、ドメインモデルを設計するとオブジェクトができ、そのオブジェクトを保存するための仕組みの1つとして ORM が存在するという事です。
まとめ
ORM を使いこなすには、
- オブジェクトを先に設計する
- オブジェクトを設計するために、ドメインモデルや DDD を理解する
- ORM のドキュメントをちゃんと読む
ことが必要です。ドメインモデルパターン以外でも ORM を利用するかもしれませんが、まずはこれが基本だと思うのでここを押さえるところから始めようと思います。
追記
(2023/06/26) 最近クリーンアーキテクチャも読んだのですが、
エンティティオブジェクトは、フレームワーク、データベース、その他の複雑さに依存しない、プレインオールドオブジェクトでなければいけない。
『Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ)』Robert C.Martin, 角 征典, 等著
と書かれていました。クリーンアーキテクチャにおいては、ドメインモデルのエンティティと ORM のエンティティは異なるもののようです2なんなら 「ORM というものは存在しない」とも書かれていました。ドメインモデルは POJO で記述し、ORM はインフラストラクチャなのでドメインモデルの外側に記述するもののようです。
ORM のエンティティとドメインモデルのエンティティを連携する場合は、リポジトリを経由して2つのエンティティのマッピングを行うようです。間に腐敗防止層を入れるイメージでしょうか。
Java の場合は MapStruct があるとはいえ、RDBMSしか使わない事がはっきりしているプロジェクトで、各エンティティのデータマッパーを用意してまでクリーンアーキテクチャにする価値はあるのかは疑問が残ります。結局は「場合による」という事なのでしょうか。