ドメイン駆動設計のリポジトリに対する考察

この記事は　[ZOZO #4 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/zozo) １3日目の記事になります。

今回は[エリック・エヴァンスのドメイン駆動設計(以下、DDD本)](https://www.amazon.co.jp/dp/B00GRKD6XU/)、[実践ドメイン駆動設計(以下、IDDD本)](https://www.amazon.co.jp/dp/B00UX9VJGW)を読み比べ、リポジトリの設計について考えたことを書いてみようかと思います。

そもそもリポジトリとは何か？

そのまま翻訳すれば、「倉庫、金庫、倉」。ドメイン駆動設計的には、集約のインスタンスを永続化しておくところと言えるでしょう。

DDD本を読むともう少し深い意味を見いだせます。
そもそもリポジトリの章は「第６章　ドメインオブジェクトのライフサイクル」の中にあり、ドメインの生成から削除される過程までのライフサイクルに関わる機能であることがわかります。

> クエリを実行して、属性に基づいてデータベース内でオブジェクトを見つけるか、もしくは、オブジェクトの構成要素を見つけて、それを再構成するというものだ。

> 概念上は、これはエンティティのライフサイクルにおける中期なのである。

> Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (Kindle の位置No.3475-3476). Kindle 版. 

この点についてはDDD本もIDDD本も同じ見解で、つまり、Factoryでオブジェクトを生成して、リポジトリで一時保存、取り出しし再構成する。ということです。

で、問題はそれをどう実装するか？

リポジトリを普通にオブジェクトを保管する場所と捉えるならば、

``` java
CreatedModel createdModel = CreatedModelFactory.create();
createdModelRepository.insert(createdModel)

CreatedModel reCreatedModel = createdModelRepository.select();
```

こんな感じが自然でしょうか？

しかし、Evansの言葉を借りれば、

> ドメイン駆動設計の目標は、技術ではなくドメインについてのモデルに焦点を合わせることによって、よりよいソフトウェアを作ることである。

> Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (Kindle の位置No.3478-3480). Kindle 版. 

なので、insertやselectと言った技術的な用語を用いずリポジトリを設計するのが望ましい。
さらに、

> あるオブジェクトを生成し、その型のすべてのオブジェクトで構成されるコレクションが、メモリ上にあると錯覚させることができるようにすること。

> Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Japanese Edition) (Kindle の位置No.3556-3557). Kindle 版. 

ということで、DDD本であげられている例は

<img width="300" alt="DDD1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150455/3110fff9-fbaa-ced3-27ef-9cff06823790.jpeg">

こんな感じで、addを使う。つまり、集合を扱うように設計するということです。

永続化されているDBが集約の集合と捉えて、レポジトリに対してaddすることで、メモリ上にあるように扱うことができるということですね。

DDD本であげられている例はこれだけですが、IDDD本を読むとSetの挙動を再現するような実装にするとあります。

## Collection指向のリポジトリ

javaのSetは重複なしの集合なので集約の集合を扱うという点で納得がいきますよね。

javaの[Set](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Set.html)のライブラリから実装を真似てみると、、、

```java
createdModelRepository.add(createdModel)
createdModelRepository.size(createdModel)
createdModelRepository.remove(createdModel)
```
まあ、いいかもですね。

って、あれ？変更して戻したいときはどうすれば？

> すでにリポジトリに登録されているオブジェクトを変更しても、「保存しなおす」必要はないということだ。コレクションに含まれるオブジェクトを変更するときのことを考えてみよう。極めて単純なことだ。まず、変更したいオブジェクトへの参照をコレクションから取得する。そして、そのオブジェクトのコマンドメソッドを実行して、オブジェクト自身に状態を変更させる。

> ヴァーン・ヴァーノン. 実践ドメイン駆動設計 (Japanese Edition) (Kindle の位置No.9220-9221). Kindle 版. 

え？無理じゃない？

> 結論としては、Hibernateのようなこの手の永続化メカニズムを使えば、昔ながらのコレクション指向なリポジトリを作れるということだ。

> ヴァーン・ヴァーノン. 実践ドメイン駆動設計 (Japanese Edition) (Kindle の位置No.9270-9271). Kindle 版. 

Hibernateなど一部のORM使ってないと無理でした。
それから、おそらくこの場合は、同じオブジェクト内で変更する必要がありそう。変更したときに新しいオブジェクト作る場合はうまくいくのかちょっと疑問が残ります・・・。。。

## 永続指向のリポジトリ

> コレクション指向の方式ではうまくいかない場合は、永続指向のリポジトリを使う必要がある。

> ヴァーン・ヴァーノン. 実践ドメイン駆動設計 (Japanese Edition) (Kindle の位置No.9463-9464). Kindle 版. 

```java
createdModelRepository.save(createdModel)
createdModelRepository.size(createdModel)
createdModelRepository.remove(createdModel)
```

こんな感じで、新規に作ったオブジェクトに対してsave、変更した際にもsaveをして保存するという挙動ですね。

こちらは実現性がありそう。

DDD本のEvans自体執筆当時おそらくここまで考えて言及したわけではないでしょう。
もちろん、技術ではなくドメインについてのモデルに焦点を合わせる設計をしていくことが望ましいのは間違いないので、できるだけコレクション指向の実装に寄せて使っているORMや永続化の仕組みに合わせて柔軟に設計していけばよいかと思います。

次の日は @JotarO_Oyanagi さんによる「データポータルとスプレッドシートで作るモンスター合体データベース」になります！自分はZOZO #3 Advent Calendar 2021の方に書きます。