📝 Packwerk調査メモ

## 📦️ Packwerk とは

[Shopify/packwerk](https://github.com/Shopify/packwerk)

> Packwerk is a Ruby gem used to enforce boundaries and modularize Rails applications.

日本語訳は以下のとおりです。

> Packwerk は、Rails アプリケーションにおける境界の強制とモジュール化を行うための Ruby 製の gem です。

つまり、**Packwerk は Rails アプリケーションをモジュラーモノリスとして構築するのを支援するツール**です。

## 導入手順

### 準備

[公式ドキュメント](https://github.com/Shopify/packwerk/blob/main/USAGE.md)に沿って導入を進めます。

まずは `Gemfile` に packwerk を追加し、`bundle install` を実行します。

```ruby
gem 'packwerk'
````

```bash
bundle install
```

次に、binstub を生成します。

```bash
bundle binstub packwerk
```

初期設定を行い、各種設定ファイルを生成します。

```bash
bin/packwerk init
```

以下の2つのファイルがルートディレクトリに作成されます。

```bash
./packwerk.yml
./package.yml
```

---

### モジュールを作成してコードを整理する

1.モジュールを格納するディレクトリを作成します
```bash
mkdir -p packs/item
```
2.パッケージ定義ファイルを作成します
```bash
touch packs/item/package.yml
```
3.`package.yml` を以下のように定義します
```yml
# このパッケージが他のパッケージに依存する場合、その依存先を明示的に dependencies に書かなければならないことを強制するか
enforce_dependencies: true

# 依存先の指定
dependencies: []
```
4.コードをパッケージ内に移動します
* Item に関連するコントローラー、モデル、spec などを `packs/item` ディレクトリ内に整理します
```bash
git mv app/models/item.rb packs/item/app/models
```
5.依存関係の違反リストを更新します
```bash
bundle exec packwerk update-todo
```
6.依存関係チェックが通るか確認します
```bash
bundle exec packwerk check
```
7.依存違反を少しずつ解消していきます

---

## packwerk コマンド

packwerkが提供しているコマンドは以下のとおりです。

| コマンド                              | 説明                                                                 |
|---------------------------------------|----------------------------------------------------------------------|
| `bundle binstub packwerk`            | Packwerk の binstub を生成します（`bin/packwerk` が作られます）     |
| `bin/packwerk init`                  | 初期設定を行い、`packwerk.yml` と `package.yml` を生成します        |
| `bin/packwerk check`        | 依存違反や定数参照の違反がないかをチェックします                    |
| `bin/packwerk update-todo`  | 現在の違反状態を `packwerk_todo.yml` に記録します（無視設定）       |
| `bin/packwerk validate`     | `package.yml` や構成ファイルの妥当性を検証します                    |
| `bin/packwerk help`         | 定義されているパッケージ（package）を一覧表示します                 |


## 設定ファイル

### packwerk.yml

Packwerk 全体の挙動を制御するためのルート設定ファイルです。

```yml
# Patterns to find package configuration files
package_paths: "packs/*"
```

### package.yml

各パッケージのルートディレクトリに配置し、そのパッケージの依存ルールや公開APIの制約などを記述します。

```yml
enforce_dependencies: true
enforce_privacy: true
dependencies:
  - packs/shared
```

項目名|説明
---|---
`enforce_dependencies`|他パッケージに依存する場合に `dependencies`に明示することを強制する
`enforce_privacy`|`public/` 以下以外のファイルを他パッケージから使うと違反にする
`dependencies`|このパッケージが依存可能他パッケージを一覧で指定する

### package_todo.yml

`bin/packwerk update-todo` により生成される、Packwerkの制約に違反している箇所が記録されるファイルです。


## Packwerkを利用したモジュラーモノリス化事例

* 株式会社くふうカンパニー
    * [モジュラモノリスを試験運用している話 \- ロコガイド テックブログ](https://techblog.locoguide.co.jp/entry/2023/08/28/171410)
* コインチェック株式会社
    * [サイロ化した金融システムを、packwerk を利用して無事故でリファクタリングした話 \- Speaker Deck](https://speakerdeck.com/coincheck_recruit/sairohua-sitajin-rong-sisutemuwo-packwerk-woli-yong-sitewu-shi-gu-derihuakutaringusitahua)
    * [認可ロジックのパッケージ化 \- モジュラーモノリスを採用してpackwerkを導入した話 \- Coincheck Tech Blog](https://tech.coincheck.blog/entry/2024/03/05/111105)
* STORES 株式会社
    * [STORES 予約 をモジュラモノリス化しました！ \- STORES Product Blog](https://product.st.inc/entry/2024/07/02/111758)
* 株式会社タイミー
    * [packwerk チェッカーとちゃんと向き合う \- Timee Product Team Blog](https://tech.timee.co.jp/entry/2024/12/18/000932)
    * [RailsでModular Monolithを選択された御社に質問したいN個の疑問 \- Speaker Deck](https://speakerdeck.com/shunsugai/railsdemodular-monolithwoxuan-ze-saretayu-she-nizhi-wen-sitainge-noyi-wen)
    * [モノリスの運用課題を解決するためにコードオーナーをSentryとDatadogに送る \- Timee Product Team Blog](https://tech.timee.co.jp/entry/2024/12/14/100000)
* 株式会社hacomono
    * [Rails x モジュラーモノリス \- Speaker Deck](https://speakerdeck.com/hacomono/rails-x-moziyuramonorisu)
* note株式会社
    * [モノリシックRailsアプリケーションを モジュラモノリスへ移行している noteの事例 \- Speaker Deck](https://speakerdeck.com/shshimamo/monorisitukurailsapurikesiyonwo-moziyuramonorisuheyi-xing-siteiru-notenoshi-li)

---

## 参考サイト

* [Shopify/packwerk: Good things come in small packages.](https://github.com/Shopify/packwerk)