こんにちは、akitoshigaです。
現在Ruby on Railsのモジュラーモノリス化を行っており、その際に利用したpacks-rails
というgemが大変便利だったのですが情報が少なかったので紹介します。
1. packs-railsとは?
一定の規則に従って、単一のRails on Railsアプリケーションをモジュール分割するgemです。
このgem単体でも利用できますが主にpackwerkと組み合わせて使われることが多いと思います。
packwerk
とはRuby on Railsの静的解析を行うgemでモジュールごとの依存関係の管理ができます。
2.一体何がすごいのか?
2.1 (ほぼ)設定不要
packs-rails
は内部でzeitwerk
というgemを利用しています。
packs-rails
の指定のディレクトリ構成に従えば、zeitwerk
のおかげで面倒な設定をせずにディレクトリ・ファイルの移動が可能になります。
zeitwerk
とはRailsでオートロードの仕組みを提供するgemのことです。
Railsのコードでいちいちrequire
しなくて良いのはこのgemのおかげです。
3. 使い方
gemをインストール後、以下の構成に従って、ディレクトリを配置するだけです。
# https://github.com/rubyatscale/packs-rails のREADME.mdより抜粋
package.yml # root level pack
app/ # Unpackaged code
models/
...
packs/
my_domain/
package.yml # See the packwerk docs for more info
package_todo.yml # See the packwerk docs for more info
app/
public/ # Recommended location for public API
my_domain.rb # creates the primary namespaces
my_domain/
my_subdomain.rb
services/ # Private services
my_domain/
some_private_class.rb
models/ # Private models
some_other_non_namespaced_private_model.rb # this works too
my_domain/
my_private_namespaced_model.rb
controllers/
views/
config/
initializers/ # Initializers can live in packs and load as expected
lib/
tasks/
spec/ # With packs-rails, specs for a pack live next to the pack
public/
my_domain_spec.rb
my_domain/
my_subdomain_spec.rb
services/
my_domain/
some_private_class_spec.rb
models/
some_other_non_namespaced_private_model_spec.rb
my_domain/
my_private_namespaced_model_spec.rb
factories/ # packs-rails will automatically load pack factories into FactoryBot, see Ecosystem and Integrations#factory_bot below
my_domain/
my_private_namespaced_model_factory.rb
my_other_domain/
... # other packs have a similar structure
my_other_other_domain/
...
ドキュメントルートのapps/
と同じ階層のpacks/
の中に任意のディレクトリ(図のmy_domain
)を配置します。
そのなかで通常のRuby on Railsアプリと同じ感覚でファイルを配置することができます。
上記のディレクトリ構成に加えてhelpers
やmailers
などの任意のディレクトリも配置することが可能ですが、assets/
に関しては別途設定が必要です。
それについては以下の記事で詳しく説明しています。
4.注意点
4.1.ディレクトリ作成は手動で行う必要がある
あたりまえですが、上記の階層構造のディレクトリを作成しなければいけないのでそれがやや手間だなと思いました。
自分はシェルスクリプトを作成して対応しました。
4.2.名前空間は共有されている
これも当たり前なのですが、モジュール分けしたからといって名前空間が新たに定義されるわけではないので、モジュール間で同一名のクラス名があったときは衝突します。
同名のクラスを定義したい場合は上のmy_domain/配下にモジュールを定義する必要があります。
既存のRailsをモジュール分割する場合は新たに名前空間を追加するのでその点が大変かと思います。
5.まとめ
注意すべき点はありますが、かなり簡単に利用できるので最初感動しました。
Railsのモジュラーモノリス化はいくつか実装手段がありますがpacks-rails
おすすめなので是非選択肢の1つとして検討してみてください🙌