Laravelをモジュラモノリスで開発する
中小規模のLaravelは、初期はモジュラモノリスで運用し、サービスが複雑/大規模になって行く過程で、モジュールをマイクロサービス化していく運用が初期開発が抑えられ、かつクリーンなコードも実現できて良いのではないのでしょうか?
モジュラモノリスとは
モノリスアプリケーション内で、ドメインモデル等を単位としてモジュールに分解し、モノリスのように1つのデプロイパイプラインだけを持ちつつも、マイクロサービスのようにシステムのモジュール化・独立性を両立したモノリスアプリケーション。
モジュラモノリスの長所
モジュラモノリスの長所として、以下のようなものが挙げられるかと思います。
- モノリスであるため、開発がマイクロサービスと比較し容易である
- コンテキストの境界がモジュール毎に明白になる
- モジュール毎にマイクロサービス化を進める事が可能である
モジュラモノリスの短所
モジュラモノリスの短所として、以下のようなものが挙げられるかと思います。
- DB周りのモジュール性がない可能性がある
- マイクロサービスと比較し、境界を適切に維持し続けるコストがかかる
- 静的解析ツールにより軽減可
- モジュール毎に異なった動作環境で動作させることができない
Laravelのモジュール化
Laravelのモジュール化するパッケージはいくつかありますが、Laravel-Modulesが一番人気だと思います。
Laravel-Modulesは、モジュール毎にLaravelの機能を作成/管理することができるパッケージです。Blog
モジュールを作成した場合は、デフォルトで下記のようなディレクトリが作成され、Laraevlの中に小さなLaravelを作成することができます。Controllers
だけでなくRoutes
やResources
もモジュール内で管理することができます。
app/
bootstrap/
vendor/
Modules/
└── Blog/
├── Assets/
├── Config/
├── Console/
├── Database/
| ├── Migrations/
| └── Seeders/
├── Entities/
├── Http/
| ├── Controllers/
| ├── Middleware/
| └── Requests/
├── Providers/
| ├── BlogServiceProvider.php
| └── RouteServiceProvider.php
├── Resources/
| ├── assets/
| ├── lang/
| └── views/
├── Routes/
├── Repositories/
├── Tests/
├── composer.json
├── module.json
├── package.json
└── webpack.mix.js
作成したモジュールは、Laravel Module Installerを使用することで別リポジトリで管理する事もできます。
Laravel-Modulesのインストール
Laravel-Modulesのインストール
$ composer require nwidart/laravel-modules
コンフィグファイルの生成
$ php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"
オートローディング設定
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "Modules/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
}
$ composer dump-autoload
モジュールの作成
モジュールはartisanコマンドによって作成することができます。
$ php artisan module:make <module-name>
カスタムネームスペース
モジュールのlang
ファイルやview
ファイルには、ネームスペースを用いてアクセスすることができます。
Lang::get('blog::group.name');
view('blog::partials.sidebar')
モジュールの境界を強制する
本来、モジュールは独立したモジュールであることが期待されますが、モジュラモノリスは結局のところモノリスのため、モジュールのクラスから他のモジュールのクラスを呼び出したりしてしまい、意図せずモジュールの独立性が失われる可能性がある問題があります。
この問題は、静的解析ツールを用いることで解決することができます。
PHPStanの場合、spaze/phpstan-disallowed-callsをインストールすることで、依存関係をコントロールすることができるようになります。
e.g. Modules\Blog
を他のネームスペースから呼び出し不可にする設定
parameters:
disallowedNamespaces:
-
namespace: 'Modules\Blog\*'
message: "Don't call form other namespaces"
allowIn:
- Modules/Blog/*
PHPStanをまだ導入されていない場合は、Larastanをlevel 0から導入することろから始めましょう。
おわりに
近年、静的解析ツールが普及してきて、コーディングルールを自動チェックできるのは非常に便利になりましたね。 現在のPHPは残念我ならマイクロサービスにはあまり向いていません。モノリスであるがマイクロサービスの特徴もあるモジュラモノリスは、非常にバランスの取れた選択肢の一つかと思います。
Discussion