【Laravel】ローカルパッケージを利用した開発戦略　その１：説明編


## はじめに

Laravel で巨大なプロジェクトを作っていくと、大量のフォルダとファイルで押しつぶされてしまいますよね....。
というときにローカルパッケージを使った開発はどうか？という提案記事です。


### 検討したソフトウェアアーキテクチャ

- モノリス
  - 一つのプロジェクトに全ての機能を実装する、いわゆる普通の作り方
  - Laravelを使うとこうなりがち...
  - そして、フォルダが肥大化しがち...
- マイクロサービス
  - 機能ごとに別のプロジェクトに分けて、連携させるやり方
  - 負荷分散ができるため、サービスの最終系としてはベスト
  - ただコストが無視できないので、気軽には始められない...
- モジュラモノリス
  - 一つのプロジェクトの中で、機能ごとにコードを分離する作り方
  - モノリスとマイクロサービスの良いとこ取り
  - [laravel-modules](https://nwidart.com/laravel-modules/v6/introduction) で実現可能
  - 良い選択！
- (参考) DDD ドメイン駆動設計
  - ビジネスを中心に考え、システムを作るスタイル（レイヤードアーキテクチャ）
  - 使用する Entity や UseCase などを明確に作成する
  - モデリングがたいへん...コードも山盛り...大規模向け...
  - Laravel の提供する構造をほぼ全て無視するため、Laravelでやる必要があるのか？から抜け出せない...


DDDが導入出来たらｽﾊﾞﾗｼｲと思うのだが、伝達コストなど、様々な属性・能力が集まるチームで進められるか？を考えると少し躊躇する...。（司令塔と、無限の余裕がほしい）

次点として `モジュラモノリス` を仮で導入した。
これは、システム開発のとても良い着地点だと思う。

しかし、route や migration など、Laravel の機能全てが分離されるため、責務が分けにくいやつらが出てくる。
また、モジュール間の繋がりも書きにくい。
加えて、パッケージへの依存度が非常上がるので、メンテナンスされなくなると〇ぬデメリットがある。



### ローカルパッケージ戦略

そこで、機能ごとにモジュールを別のパッケージとして記載し、プロジェクトに組み込むのはどうかと考えた。
モジュラモノリスの、ローカルパッケージ版である。

![drawio (21).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833190/dfcdebb1-d540-5acb-1762-4c9c89840e6e.png)

汎用的な、例えば印刷するモジュールを、パッケージとして本体のプロジェクトから切り出すイメージです。
アーキテクチャのイメージはこんな感じ。

![drawio (22).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833190/34f16e58-3b90-dbdf-3900-6593f2a60bb3.png)

- `Main Project` は、ルーティングや権限を管理する
- `Sub Package` は、機能、ビジネスロジックを提供する

こうすることで、各部分の責務が明確になり、見通しの良いコードになると考えた。
全体のルーティングや、モジュール間の繋がりは、mainに書くことでぱっと見で管理しやすい。

なお、Laravel の Package は、書こうと思えばルーティングまで全て書くことができるので、モジュラモノリスと同じように利用することもできます。
パッケージ化することで、そこだけ別タスクとして切り出したり、丁寧にテストを書いて封印し、品質を保証するなど、様々な利点がありそうです。



## 導入

必要なもの：
- `php` `composer` コマンドが動作する環境
- ある程度のLaravelの知識 (触れません)

※ 焦点をブラさないため、 Docker は使いません

今回はこんな感じの構成にします。

```diff
  laravel-local-package
  ├ app
  ├ ...
+ ├ package
+ │ ├ sub-module
+ │ ├ ...
  ├ ...
```

`Main Project` が `laravel-local-package` という名前。
`Sub Package` が `sub-module` という名前。


### `Main Project` の作成

既にあるものを利用しても大丈夫です。

```bash
$ php -v
PHP 8.2.0 (cli) (built: Nov 27 2023 09:22:06) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
$ composer -V
Composer version 2.6.5 2023-10-06 10:11:52

# laravel install
$ composer create-project laravel/laravel laravel-local-package "11.*" --prefer-dist
$ cd laravel-local-package

$ php artisan serve
```
=> `http://127.0.0.1:8000` が表示されたらOK  


### `Sub Package` の作成

Laravel でパッケージを作成する場合、`Spatie` 神のテンプレートを使うのが最も簡単。  
このテンプレート自体はMITライセンスだが、[有償のトレーニング動画](https://spatie.be/courses/laravel-package-training-v2/starting-a-laravel-package-using-the-skeleton) が用意されている。

https://github.com/spatie/package-skeleton-laravel

```bash
# create package
$ git clone https://github.com/spatie/package-skeleton-laravel ./package/sub-module
$ cd ./package/sub-module

# もし PHP v8.2 を使用する場合は、コミットを切り替える (上記は PHP v8.4 推奨)
# 他のバージョンは以下から探す
# ref: https://github.com/spatie/package-skeleton-laravel/commits/main/
#
$ git checkout 9d60f35

# git in git になって使いにくいので、好みで git を消す
$ rm -rf ./.git
```

準備ができたら `configure.php` でパッケージの初期設定を行う。


項目は `<name> (<username>, <email@xxx.com>)` で対応している。
パッケージ名は `<Vendor namespace>/<Package name>` となる。
`Author` は作成者、`Vendor` は社名を入れればよい。

未入力の場合、かっこの中身がそのまま登録される。
今回はローカルパッケージなので、まぁ適当でも問題ない。  

PhpStan と Pint は入れておこう。

:::note alert
空欄があると `composer install` でコケるので注意！ (しかも分かりにくい)
:::

```bash
$ php ./configure.php
Author name (xxx): sigeta
Author email (xxx): sigeta@example.com
Author username: sigeta
Vendor name (xxx): crest
Vendor username (xxx): crest
Vendor namespace (Crest): 
Package name (sub-module): 
Class name (SubModule): 
Package description (This is my package sub-module): 
Enable PhpStan? (Y/n): Y
Enable Laravel Pint? (Y/n): Y
Enable Dependabot? (Y/n): n
Use Ray for debugging? (Y/n): n
Use automatic changelog updater workflow? (Y/n): n

Modify files? (Y/n): Y
Execute `composer install` and run tests? (y/N): y

Let this script delete itself? (Y/n): Y
```

`Let this script delete itself?` まで表示されたら導入完了。



### `Main Project` に `Sub Package` を紐づける

main の `composer.json` に、このパッケージを紐づける。

プロジェクトルートにディレクトリを移動して、

```bash
$ cd ../../

$ composer config repositories.local path ./package/sub-module
$ composer require "crest/sub-module @dev"
```

パッケージ名が分からない場合は、パッケージ側の `composer.json` の `name` キーを読む。
`@dev` を付けることで、`vendor` にシンボリックリンクが張られ、リアルタイムで変更が読み取られる。

もちろんモジュールは git で管理することもできる。
参考: [Repositories \- Composer](https://getcomposer.org/doc/05-repositories.md)



### 動作確認

コマンドが用意されているので、疎通確認として main で実行する。
`package/sub-module/src/Commands/SubModuleCommand.php`  

```bash
$ php artisan sub-module
All done
```


## パッケージの開発ガイド


:::note
あまりにも長くなったので、次の記事へ
:::

https://qiita.com/sigeta/items/279c844c5159848eb286