この記事はLaravel Advent Calendar 2020の18日目です。
はじめに
ドメイン駆動設計で開発していてインフラストラクチャ層がとっ散らかりがちになるのが悩みの種でした。
『実践ドメイン駆動設計』の第9章にモジュールを使ってクラスを整理する方法が書かれていますが、ドメイン層のモジュールについての話がほとんどで、インフラストラクチャ層のモジュールについては書かれていません。
そんな折に見つけた『Domain-Driven Design in PHP』という本に、いいなと思うインフラストラクチャ層のモジュール設計が書かれていたので紹介したいと思います。
『Domain-Driven Design in PHP』で推奨されているインフラストラクチャ層のモジュール設計
この本ではインフラストラクチャ層にドメイン層と同じ構成のモジュールを作ることを推奨しています。
|-- Domain
| `-- Model
`-- Infrastructure
`-- Domain
`-- Model
ドメイン層のインターフェースをインフラストラクチャ層で実装するときは、対応するモジュールに配置します。
|-- Domain
| `-- Model
| `-- Bill
| `-- BillRepositoryInterface.php
`-- Infrastructure
`-- Domain
`-- Model
`-- Bill
`-- EloquentBillRepository.php
私がこの設計をいいなと思った理由は、インターフェースの実装がどこにあるのかわかりやすくなる点と、インフラストラクチャ層のモジュール名にもユビキタス言語が使われるようになる点です。
ORMなどドメイン層に対応しないものは、その技術に関連したモジュールに配置します。
Infrastructure
|-- Domain
`-- Persistence
`-- Eloquent
`-- Models
`-- Bill.php
本には書かれていませんでしたが、アプリケーション層のインターフェースをインフラストラクチャ層で実装するときもドメイン層のときと同じようにするのがいいと思います。
|-- Application
| `-- DataTransformer
| `-- Bill
| `-- BillDataTransformerInterface.php
`-- Infrastructure
`-- Application
`-- DataTransformer
`-- Bill
`-- BillLaravelPaginatorDataTransformer.php
Webアプリケーションフレームワークとの付き合い方
この本にはWebアプリケーションフレームワークとの付き合い方についても書かれています。
Webアプリケーションフレームワークを使う場合は、インフラストラクチャ層にデリバリーメカニズム(Web、API、コンソールなど)ごとのモジュールを作り、さらにその中にフレームワークごとのモジュールを作ることを推奨しています。
Infrastructure
|-- Delivery
| |-- Api
| | `-- Laravel
| |-- Console
| | `-- Symfony
| `-- Web
| `-- Silex
`-- Domain
上記の例ではAPIにLaravelを使い、コンソールにSymfonyを使い、WebにSilexを使っています。
ユーザーインターフェイス(コントローラやビューのことだと思います)に関しては、各フレームワークのモジュールに配置することを推奨しています。
本では各フレームワークのモジュール内部については特に書かれていませんでしたが、
Frameworks should obey you, and not the other way around. (フレームワークがあなたに従うべきであり、その逆ではない。)
との言葉があったので、各フレームワークのモジュール内部はフレームワークの規約に縛られることなく自由に設計していいということだと思います。
Laravelの例
以下は本に書かれていることではないですが、本を読んでみてLaravelを使う場合どうするか自分なりに考えてみました。
Laravelモジュールの中に自分のアプリケーションで使うLaravel関連のファイルを好きなように配置します。
Infrastructure
`-- Delivery
`-- Web
`-- Laravel
|-- Controllers
|-- Middleware
|-- Providers
|-- Requests
|-- resources
| |-- fonts
| |-- js
| |-- lang
| |-- less
| `-- views
`-- routes
これらのファイルをLaravelに使わせるには設定ファイルを書き換えることになります。
また、設定ファイルを書き換える以外の方法として、パッケージ機能を使ってLaravelに公開することもできると思います。
この方法であれば設定ファイルを書き換えることすら不要になるので、Laravelをほとんど素のままで使うことができるはずです。
Laravelのドキュメントには書かれていませんが、ミドルウェアやイベントもパッケージとして公開できます。
ミドルウェアはIlluminate\Support\ServiceProvider
を継承したサービスプロバイダーを作って、boot
メソッドの中でLaravelのAPIを使うことで登録できます。
public function boot()
{
$this->app['router']->aliasMiddleware('my_middleware', MyMiddleware::class);
}
イベントもIlluminate\Foundation\Support\Providers\EventServiceProvider
を継承したサービスプロバイダーを作れば、あとは普通にイベントを登録するときと同じように登録できます。
protected $listen = [
// ...
];
おわりに
『Domain-Driven Design in PHP』に書かれていたインフラストラクチャ層のモジュール設計について紹介しました。
また、Laravelを使う場合どうするか自分なりに考えてみました。