Repositoryは「永続化層」ではない

Repositoryと聞いて、多くの人がまず思い浮かべるのは次のような役割です。

  • データベースへのアクセスを隠蔽する
  • CRUD処理をまとめる
  • ORMやSQLの詳細を隔離する

これらはRepositoryの“効果”ではありますが、Repositoryそのものの本質ではありません。

Repositoryは、永続化のための仕組みではなく、集約を扱うための抽象です。もしRepositoryを「DB操作クラス」として設計してしまうと、DDDの重要な意図はほぼ失われます。


Repositoryが扱うのは「集約」である

前章で述べた通り、集約は「同時に守るべき判断とルールの単位」でした。

Repositoryは、その集約を

  • 取得する
  • 保存する

ための唯一の窓口です。

重要なのは、Repositoryが

  • Entity単体
  • テーブル単位のレコード

を扱う存在ではない、という点です。Repositoryが扱うのは、常に意味を持った集約全体です。

この制約があるからこそ、集約の不変条件は安全に保たれます。


なぜRepositoryを介さずに触ってはいけないのか

もし集約の内部オブジェクトを、Repositoryを介さずに直接取得・更新できてしまうと、次のような問題が起こります。

  • 不変条件を守らずに状態を書き換えられる
  • 集約の境界が形骸化する
  • 「正しい操作」が分からなくなる

これは、設計が破綻する典型的なパターンです。

Repositoryは、「この集約は、こういう単位でしか扱えない」というルールをシステム全体に強制する役割を持っています。


interfaceを切ることが目的ではない

Repositoryはしばしばinterfaceとして定義されます。そのため、「Repository = interface」という理解が広まりがちです。

しかし、interfaceを切ること自体は目的ではありません。

Repositoryを抽象として定義する理由は、

  • 集約の概念をインフラから切り離すため
  • モデルの言葉で取得・保存を表現するため

です。

もしinterfaceを切ったにもかかわらず、

  • findById
  • save
  • delete

といった汎用的なCRUDメソッドしか存在しないのであれば、そのRepositoryはドメインの言葉をほとんど語っていません。


良いRepositoryは「問い」を持っている

良いRepositoryは、ドメインの問いをそのままメソッドとして表現します。

  • 有効な注文を取得する
  • 処理待ちの支払いを探す
  • 特定の条件を満たす集約を取得する

これらは、SQLやクエリの話ではありません。ドメインが何を知りたいかという問いです。

この形でRepositoryを設計すると、UseCaseのコードは自然言語に近づいていきます。


RepositoryとUseCaseの健全な距離

UseCaseは、Repositoryを使って集約を取得し、操作し、結果を保存します。

ここで重要なのは、UseCaseが

  • 集約の内部構造を知らない
  • 永続化の詳細を知らない

という状態を保つことです。

UseCaseが知っているのは、

  • どの集約を使うか
  • どの操作を呼ぶか
  • 結果を保存する必要があるか

だけで十分です。

この距離感が保たれていると、UseCaseは「流れ」に集中でき、判断はモデルと集約に委ねられます。


Repositoryを薄くしすぎない

「Repositoryは薄く保つべきだ」という言葉も、誤解されやすい表現です。

Repositoryが薄いとは、ロジックを持たないことではありません。 ドメインの「判断」を持たないことです。

Repositoryは、ドメインモデルを永続化の世界に橋渡しする責務だけを持ちます。

  • キャッシュ戦略
  • データソースの切り替え
  • 永続化の最適化

これらはRepositoryの内部にあって構いません。重要なのは、それらがUseCaseやモデルに漏れ出さないことです。


この章のまとめ

Repositoryは、永続化のための仕組みではありません。Repositoryは、集約を集約として扱うための境界です。

次章では、Repositoryを使って処理の流れを組み立てる存在である「UseCase」について掘り下げていきます。そこで、DDDとアプリケーション層の関係が、より明確になります。