Modular Monolith(モジュラーモノリス)の記事とか色々読んでみた

最近Modular Monolith(モジュラーモノリス)というアーキテクチャについての記事を色々と読んでいます。
個人的に面白いアーキテクチャかなと思っているのでメモがてらまとめてみたいと思います。

目次

Modular Monolithとは

そもそもModular Monolithとはですが、モノリスアプリケーション内で、ドメインモデル等を単位としてモジュールに分解することにより、モノリスのように1つのデプロイパイプラインだけを持ちつつも、マイクロサービスのようにシステムのモジュール性/独立性を高めることを目指すアーキテクチャです。

マイクロサービスだとOrderサービスやShopサービス等が独立したAPIとして分割されることでドメインモデルの境界を定義していますが、モジュラーモノリスでは同じことを同一コードベース内でモジュールとして切り出し、モジュール間でのやりとりは公開用のI/Fを用いて行うなどし、各モジュール間の依存関係を明確にすることで行っています。

モノリスとマイクロサービスの間に立つアーキテクチャで、記事でもいきなりモノリスからマイクロサービスに移行するのではなく、まずモジュラーモノリスに移行してそこからマイクロサービスに移行した方が良いといった内容が述べられています。

Deconstructing the Monolith: Designing Software that Maximizes Developer Productivity

巨大なモノリスとして開発されていたRuby On Rails製のSpotifyをどのように分割し、新たなアーキテクチャに刷新したかについて述べられています。

記事では、モノリスとマイクロサービスのメリットとデメリットを論じた上で、以下のような理由でモジュラーモノリスを選択したと述べられています。

We wanted a solution that increased modularity without increasing the number of deployment units, allowing us to get the advantages of both monoliths and microservices without so many of the downsides.

コンポーネント間の境界の定義や疎結合といった事を実現しつつも、マイクロサービスによってもたらされるデータの整合性やテスト、デプロイの複雑さを避けるための選択肢としてモジュラーモノリスを選択したようです。

The first issue they chose to address was code organization. At this time, our code was organized like a typical Rails application: by software concepts (models, views, controllers). The goal was to re-organize it by real-world concepts (like orders, shipping, inventory, and billing), in an attempt to make it easier to locate code, locate people who understand the code, and understand the individual pieces on their own. Each component would be structured as its own mini rails app, with the goal of eventually namespacing them as ruby modules. The hope was that this new organization would highlight areas that were unnecessarily coupled.

Railsの実装は正直あまり理解できていませんが、各モジュールを独自のRailsアプリケーションとして構築し、分割されたモジュールに対しては、パブリックに提供される公開I/Fを通してのみアクセスすることにより、ドメインモデル事の単一責任や疎結合、モジュール性といった所を実現しているようです。
マイクロサービスであれば独立したサービスを作ることで実現してますが、それを同一コードベースで実現しています。

We developed a tool called Wedge in-house, which tracks the progress of each component towards its goal of isolation. It highlights any violations of domain boundaries (when another component is accessed through anything but its publicly defined API), and data coupling across boundaries.

またドメイン境界の違反等を検知するためにWedgeと呼ばれるツールを開発する事で、コンポーネント間の依存関係を明確にしているようです。

This would result in runtime errors if it tried to access code in a component that it had not declared a dependency on. We could also trigger runtime errors or failing tests when components are accessed through anything other than their public API.

そして今後の話ですが、各コンポーネントが明示的に依存している他のコンポーネントのみを利用するようにするために、依存関係を宣言していないコンポーネントのコードにアクセスしようとした際にはエラーを発生させるといったことも検討しているようです。

確かにここら辺の境界を守らせたり、依存関係を明確にする仕組みは独立したサービスにはなっていない分、モジュラーモノリスではマイクロサービス以上にしっかりしていた方が良い気はします。

だいぶ先の話になりますが、Shopifyは今回モジュラーモノリスを採用しましたが、モノリスとマイクロサービスの間となるアーキテクチャなため、数年後にここからマイクロサービスへ移行してどうだったか、あたりの話が早く聞きたいです。
モジュールとして切り出してる箇所をマイクロサービスに移行していけばいい気がするので、マイクロサービス移行で難しい、どの単位でサービスを切るかに関しては既にある程度答えが出ている分スムーズな気がしますね。

個人的にはモノリスとマイクロサービスの間となるアーキテクチャは需要があると考えているので、モジュラーモノリスでなくても、モノリスとマイクロサービスの間に位置するようなアプローチを採用する例が今後も増えてきそうだなと思っています。

The Modular Monolith: Rails Architecture

本記事では具体的なRuby On Railsでの実装等についての内容です。
Ruby On Rails自体に詳しくないので、流し見した程度ですが、具体的な実装方法が紹介されているので、別の言語やFWでの実装にも参考になるかもしれません。

以下の記事もおすすめです。
"The Modular Monolith: Rails Architecture"を読んだ

Modular Monoliths — A Gateway to Microservices

既に紹介している記事の内容とそこまで差分はないですが、この記事の中で出てくると図と以下の文章は正しくModular Monolithsが実現したいことを表しているのではないかなと思います。

this scheme is nearly indistinguishable, architecturally, from a microservice.

モジュラモノリスで表現する複雑なドメイン領域と境界

【2020/10/25追記】

モジュラーモノリスの実現方法についてのスライドです。
以下のブログ記事で知りました。

チーム内でモジュラーモノリスを推そうとした時に、自分も実際にどう作っていくかなどがいまいちピンと来ておらず少し話づらかったりしたのですが、このような導入例とか実装例があるとイメージつきやすいですし、モノリスアダプタなどの詳細な設計やディレクトリ構造の事例が増えるのはありがたいですね。

スライドにも記述がありましたが、モジュラーモノリスでコンテキスト境界を意識したドメイン設計を実現できて、かつその境界同士の独立性が担保出来るなら、改めてチーム規模によってはマイクロサービスより良い選択肢になり得るんだろうなと。
特にスタートアップなどプロダクトの初期段階ではドメインモデル自体が頻繁に変更されるでしょうし、メンバーやチーム数が少なくデプロイのスケジュールが容易に調整可能なら、マイクロサービスにしなくてもといった感じですね。

自分はここ1,2年、ID連携システムのフルリプレイスに関わっており、リプレイスを進めていく中で少しづつマイクロサービスっぽい構成にしていますが、チーム規模を考えると、API分割していた結果サービスやパイプラインの数が過剰だなと感じたり、レイテンシ/パフォーマンスの心配だとか色々考えることも多く、リリース頻度もID連携システム全体で考えても大した数ではないので、モノレポとかモジュラーモノリスの方が適していたのかなーと改めて考えてしまいました。

終わりに

記事だけでなくYoutubeにモジュラーモノリスについて取り上げたカンファレンスの動画もあったりしますが、紹介してる記事で概要を掴むことは出来たかなと思います。

個人的には世の中のアプリケーションやシステムのほとんはマイクロサービスにするほどでもなくて、とはいえモノリスでは辛いといった規模も多いと思っており、その場合にはモジュラーモノリスのようなアプローチもありなのかなと思ったりしました。
後は記事で言及されてる通り、将来的なマイクロサービスへの移行を視野に入れ、移行をやりやすくするためにとかですね。
モノリス内でモジュールや境界といった概念を持ち込んでおくことは、将来のマイクロサービス移行を考慮しても十分やる価値はありそうです。