$ tree
.
├── config # 環境変数から読み込む設定を管理。
├── database # DBへのクエリの実行を行う。repositoryのインターフェースを満たす。
├── docs # ドキュメント。
├── domain
│ ├── entity # ドメインのエンティティモデルやロジック。
│ └── repository # 永続化を責務とするリポジトリのインターフェース。
│ └── service # エンティティ単体では表せないロジック。
│ └── spotify # Spotify Web APIのインターフェース。
├── main.go # エントリーポイント。
├── mysql # MySQLのスキーマを管理。
├── spotify # Spitfy Web APIのクライアント。
├── usecase # 複数のドメインロジックを組み合わせて、実現したい一連の動作を行う。エンドポイントと1対1対応する。
└── web
├── handler # HTTPリクエスト・レスポンスが責務。ロジックは持たない。
└── router.go # ミドルウェアやルーティングの設定を行う。
web/router.go
↓ 受け取ったHTTPリクエストに対応するハンドラー関数を呼ぶ。
web/handler/*.go
↓ クエリパラメータやリクエストボディなどHTTP固有のデータを取得・検証を行い、
↓ 対応するユースケース関数を呼ぶ。
↓ これ以降はHTTP固有の構造体などを使ってはいけない。
usecase/*.go
↓ ドメインのロジックやリポジトリを使って、実現したい処理を行う。
↓
↓ → → → → → → → ↓
domain/* database/*
重要なのは、database packageがdomain packageしか依存していないことです。 ここではインターフェースを使って、依存性の逆転(DIP)を行っています。
依存性を逆転することで、
- 本来関係ないデータの永続化とロジックを明確に分割できる
- DBの修正の影響範囲がdatabase package内にとどまる
- テスト時にモックに差し替えることでDBにデータを用意する必要がない
などのメリットがあり、保守性や変更容易性が高くなります。
main.go
↓
web
↓
usecase
↓
domain/entity, domain/repository, domain/service
↑
database
エンティティはアプリケーションが扱う世界における値や振る舞いを一つにまとめたモデルです。
例えば、セッションは皆で曲を聞き合うという行動をモデル化したエンティティです。 セッションはこれから再生する曲の情報などを保持できます。また、「曲を追加する」という振る舞いも担当します。
参考 : DDD基礎解説:Entity、ValueObjectってなんなんだ
ドメインサービスは一つのエンティティ単体では表せない振る舞いを扱うものです。
例えば、「複数のセッションから自分が参加しているセッションを探す処理」は一つのセッションエンティティ単体では実現できません。
ユースケースは複数のドメインロジックを組み合わせてアプリケーション固有の自動化された機能を実装します。
例えば、「指定されたセッションIDを持つセッションに参加する」というユースケースは、
- セッション情報を取得
- ユーザがセッションの参加条件を満たしているかチェック
- セッションに参加
というドメインロジックをまとめたユースケースです。
対して、ドメインロジックの特徴はこのアプリケーションが存在しなくても存在する動作ということです。 たとえ、紙でセッションを管理しても「曲を追加する」といった振る舞いは存在します。
自動化された流れを書くのがユースケース、一つ一つの独立した振る舞いを表すのがドメインと考えると分かりやすいと思います。