DDD,クリーンアーキテクチャ,Laravel,GitHub Actionsを学習するためのアプリケーションです.
LaravelはActiveRecordパターンのフレームワークのため,DDDと組み合わせるためには,一工夫必要です.
↪️ 参考:
技術記事の記録共有作業をドメインとします.
QiitaやZennが解決しようとするドメインと同じになる想定です.
ドメインの種類 | 具体例 |
---|---|
コアドメイン | 記事記録共有作業 |
サブドメイン | comming soon... |
coming soon...
絶賛更新中のユースケース図を、 こちらのディレクトリ で管理しております.
絶賛更新中のオブジェクト図を、 こちらのディレクトリ で管理しております.
絶賛更新中のドメイン図を、 こちらのディレクトリ で管理しております.
クリーンアーキテクチャを採用します.
appディレクトリは,クリーンアーキテクチャを意識して,以下の通りに構成しております.
各レイヤーの実装パターン間の依存関係もクリーンアーキテクチャに沿って実装しております.
APIとして使用するため,インターフェース層のプレゼンター,ユースケース層のアウトプットバウンダリを廃止しております.
これに伴い,ユースケース層のインターラクターは,プレゼンターではなくレスポンスモデルを返却するようにしております.
project
└── app
├── Console
├── Constant # 定数パターン
├── Domain # <<< ドメイン層 >>>
| └── Foo # 任意のルートエンティティ
| ├── Criterion # ドメイン検索条件(検索条件パターン)
| ├── Events # ドメインイベント(Laravelの機能に依存することを許容)
| ├── Entities # エンティティ
| ├── Repositories # インターフェースリポジトリ(実装リポジトリと対応)
| ├── Services # ドメインサービス
| └── ValueObjects # 値オブジェクト
|
├── Exceptions # 例外
├── Http # <<< インターフェース層 >>> (Laravelによる制約で,Httpディレクトリの名前と構成はそのまま)
| ├── Authenticators # 認証コントローラ
| ├── Controllers # コントローラ
| | └── Foo # 任意のルートエンティティ
| |
| ├── Middleware # ミドルウェア
| └── Requests # バリデーション
|
├── Infrastructure # <<< インフラストラクチャ層 >>>
| └── Foo # 任意のルートエンティティ
| ├── DTOs # エンティティ詰め替えオブジェクト(Eloquentを継承)
| ├── Listeners # リスナー
| ├── Services # インフラストラクチャサービス
| └── Repositories # 実装リポジトリ(インターフェースリポジトリと対応)
|
├── Providers # プロバイダー
├── Traits # トレイト
└── UseCase # <<< ユースケース層 >>>
└── Foo # 任意のルートエンティティ
├── InputBoundaries # インプットバウンダリ
├── Inputs # インプット(リクエストモデル.LaravelのFormRequestと名前が被らないように命名.)
├── Interactors # インターラクター
└── Outputs # アウトプット(レスポンスモデル)
イメージのビルドとコンテナの構築を行います.
$ docker-compose up -d
起動中のコンテナ内でコマンドを実行します.
ここでは,appサービスにてライブラリをインストールします.
$ docker-compose exec app bash
root@dawl-laravel:/var/www/ddd-backend-with-laravel# make composer-install
DBのレコードの状態を初期化し,また初期データを挿入します.
3人のユーザと,各ユーザに紐づくデータが作成されます.
$ docker-compose exec app bash
root@dawl-laravel:/var/www/ddd-backend-with-laravel# make fresh-seed-db
本アプリケーションにはフロントエンドがありません.
その代わりに,Postman を使用してフロントエンドを擬似的に再現します.
Postmanのエクスポートファイルを,以下のリンクから取得できます(随時更新中!!🙇️)
エクスポートファイル:https://www.getpostman.com/collections/a83d435cb5ee98ce1b84
- Postmanのエクスポートファイルをコピーし,自身のPostmanにインポートします.
- DBレコード初期化のコマンドを実行します.
- DBのusersテーブルを確認し,初期データのユーザのメールアドレスとパスワードをコピペします.
- loginエンドポイントにて,メールアドレスとパスワードをJSONに割り当て,POSTリクエストを送信します.
- Form認証(Cookieベースの認証)が成功し,homeエンドポイントにリダイレクトします.
- 以降,好きなエンドポイントにリクエストを送信できます.
Laravelでは,セッション中の毎リクエストでCSRFトークンが変化します.
そのため,Postmanの Pre-requestスクリプト に,事前にルートパスにリクエストを送信してCSRFトークンを取得する処理を設定しています.
PHP-CS-Fixer を使用して,ソースコードを整形します.
GitHub Actionsを使用して,プッシュされたソースコードを整形し,再プッシュするようにしています.
開発環境でこれを実行する場合は,以下を実行します.
$ docker-compose exec app bash
root@dawl-laravel:/var/www/ddd-backend-with-laravel# make fixer-fix
larastan を使用して,ソースコードの静的解析を実行します.
予定:GitHub Actions上で静的解析を実行し,一つでも問題が検出されたら怒られるようにしたい...
$ docker-compose exec app bash
root@dawl-laravel:/var/www/ddd-backend-with-laravel# make stan-analyse
Makefileにターゲットを定義しています.
Laravelの一連のキャッシュ削除コマンドを全て実行します.
$ docker-compose exec app bash
root@dawl-laravel:/var/www/ddd-backend-with-laravel# make clear-all-cache
DDD,デザインパターン,Laravel を組み合わせました.
ActiveRecordパターンであるLaravelでは,ドメイン層のモデルとテーブル構造が相互に依存します.
多くのメリットがある一方で,ドメイン層が変化するたびにテーブル構造に影響を与えてしまうというデメリットがあります.
これは逆も然りです.
ドメイン層の柔軟なスケーリングを考慮すると,LaravelにDDDを組み込むことが望ましいです.
ただし,ActiveRecordパターンはDDDと相性が悪いです.
DDDはActiveRecordパターンではなくRepositoryパターンと相性が良いです.
RepositoryパターンをLaravelに適用するために,Eloquentを継承したDTOを用意しています.
ユースケース層でエンティティを構成し,これをドメイン層のインターフェースリポジトリを介してインフラストラクチャ層に渡すと,エンティティがDTOに詰め替えられます.
DTOはEloquentを継承しているため,詰め替えられたデータに応じて,データベースを操作できます.
DDDを実現するために,最初レイヤードアーキテクチャが考案されました.
クリーンアーキテクチャは,さらにこのレイヤードアーキテクチャに対して,『依存性逆転の原則』を組み込んだものです.
依存性逆転の原則を満たすために,インターフェースに依存するように実装する必要があります.
参考:https://little-hands.hatenablog.com/entry/2017/10/11/075634
『依存性逆転の原則』を満たすために,まず,ドメイン層にインターフェースリポジトリを置き,インフラストラクチャ層にその実装を置きます.
また,ユースケース層では,ドメイン層のインターフェースリポジトリを介して,インフラストラクチャ層の実装リポジトリをコールするようにします.
これにより,ユースケース層とインフラストラクチャ層の両方が,ドメイン層のインターフェースに依存するようになり,依存性逆転の原則を満たすことができます.