概要
数年前にマイクロサービスが流行ったとき、Rails界隈でもマイクロサービス対応が盛んに行われました。 しかし、Railsとマイクロサービスの相性はあまり良くなく、分散されたモノリスになりがちです。 そんなときRailsを使った大規模なプロダクトであるSpopifyが モジュラーモノリス という手法を提案しました。 これはモノリスの中でモジュール分割することにより、マイクロサービスの利点の一つである認知負荷を下げる試みです。 aumoでモジュラーモノリス対応を始めたため、その事例について紹介します。
サービスの成長とモノリスの限界
aumoは当初メディア事業から始まりました。 事業の成長に伴い、 マーケティングSaaS 、 デジタルギフト など様々なサービスを手がけるようになりました。 これらは、Ruby on Railsのモノリスで提供しています。 しかし、それぞれのサービスは異なるドメイン知識が必要となるため、認知負荷が高い状態です。 そこで、モノリスを解体しようとしました。
まず初めに、マイクロサービスに分割できないか調査を行いました。 しかし調査をしたところ、Railsでマイクロサービス化を行なった場合、 結果としてモノリスのような密結合のマイクロサービスが生まれる 「分散モノリス」と呼ばれるアンチパターンに陥るケースが多いようです。 他社の事例 1 では、モジュラーモノリス対応に切り替えるケースが多いようです。
モジュラーモノリスでは、モジュールに分割して、モジュールを疎結合にします。 これにより、認知負荷を下げます。 aumoのメディアの担当者は、デジタルギフトのドメイン知識やコードを意識しないで済むようになります。 当初の目的である認知負荷を下げることができるため、 マイクロサービスではなくモジュラーモノリス対応を行うことにしました。
gemとpacks
モジュラーモノリスは概念だけでなく、ツールが用意されています。 Rubyでモジュールというとgemを思い出しますが、 packsというモジュール機構が用意されています。 packsはrailsアプリケーションのルートディレクトリにpacksというディレクトリを作って、 そこにモジュールを格納します。 2
railsからpacks以下のコードを読み込むようにパスを通すことで、 デフォルトのapp以下と同様に実装を進めることができます。 gemと異なりリポジトリの中にモジュールを作るため、 従来のCICD機構を使い続けることができます。 また、モジュール間の結合状況を静的解析するツールがあるため、開発を止めずに少しづつ移行を進めることができます。
環境構築
packsのREADME を参考にモジュラーモノリスの環境構築を行います。 まずGemfileに以下の行を追加して、bundle installします。
# moduler monolith handling
gem 'packs-rails'
gem 'packs'
次にモジュール間の依存関係を静的解析するツールであるpackwerkを初期化 3 します。
bundle binstub packwerk
bin/packwerk init
モジュール作成
空のモジュールを作成します。次のコマンドでは、gift という名前のモジュールを作成します。
./bin/packs create packs/gift
作ったモジュールにファイルを移動させます。次のコマンドでは、path/to/file.rb をgiftモジュールに移動させます。
./bin/packs move packs/gift path/to/file.rb
必要なファイルを移動させたら、依存関係を静的解析 4 します。
root@dev:/var/source/app# ./bin/packs check
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
..........................................................E......E.....E........................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
................................................................................................................................................................
..............................................................................................................................................................
� Finished in 55.37 seconds
14 offenses detected
No stale violations detected
公式ドキュメント の解消法を参考にして、 可能な限り違反を解消します。正当な参照や修正が難しい参照は設定ファイル(package_todo.yml)に記載して、違反報告されないようにします。 以下のコマンドで、既存の違反を全て設定ファイルに書き込みます。
./bin/packs update
� Packwerk is inspecting 3838 files
..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
� Finished in 30.06 seconds
No offenses detected
✅ `package_todo.yml` has been updated.
その後再度依存関係チェックを回すと、設定ファイルに記載した違反は除外してチェックされます。 直前にupdateした場合、違反は全て設定ファイルに含まれているため、違反無しという結果となります。
./bin/packs check
..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
� Finished in 55.59 seconds
No offenses detected
No stale violations detected
モジュール外部からアクセスされるファイルはpublicディレクトリ(packs/gift/app/public/)に移動させることで、 より分かりやすくなります。
./bin/packs make_public packs/gift/path/to/file.rb
./bin/packs update
様々なコマンドを打ちましたが、結局ファイルの場所を移しただけなので、 railsアプリケーションは変更前と同様に動作します。時間のあるときに少しずつ修正していくことで、モジュールをより疎結合にすることができます。疎結合にすることで、当初目標の認知負荷の軽減を達成できます。
まとめ
既存のモノリスをマイクロサービスに分割することは、大きな工数がかかります。 しかし、モジュラーモノリスは、ツールも整備されているため、少ない工数で対応可能です。 とりあえずファイルを移動させておいて、時間のかかる依存関係解消は少しずつ進めることもできます。 少しでも皆様のお役に立てれば幸いです。