モジュラモノリス徹底解剖〜実践者から学ぶLunch LT〜
LT①『非モジュラーモノリスからモジュラーモノリスへのステップ』
株式会社ナレッジワーク 川中 真耶さん(@mayahjp)
- 6,7人ぐらいのところから20数名になった。めっちゃ困る前に対策したいという背景
- マイクロサービスももちろん検討した
- △は工夫すれば○と同等になると考えている
- Goでinternalディレクトリを切ってprivate可視性をつうる
- 最初からゴールにいくのは無理で、ディレクトリだけ分けるようにしたが、諦めることがたくさんあった。循環依存があったり、すべてのモジュールに依存しているスーパーファイルみたいなやつがいたりする
- 正しくモジュール化されたものが増えていく
- 今はこうなっている
- RDB
- 外部キーなどもあり容易には剥がせない
- モジュールをまたがる処理は?
- またがらないように作る。serviceレイヤがモジュールを呼び出すだけにする
- モジュールの粒度・数
- 意味的にまとまった小さいものをバラバラつくる
- 意味のある分け方とは?
- tenantとかuserとかナレッジというファイル相当のデータを格納するスペースは密なので分けられない
- 30~40ぐらいのモジュール数
### Q&A
- モジュールの大きさ(ファイル数とか)、数はどんな感じでしょうか?
- 大きいものは 50 ぐらいあったりしますが、小さいものは 3~4 ファイルで済んでいます
- Goを利用しているということでしたが、モジュールごとにバイナリが分かれるイメージでしょうか?ソースの階層がモジュール(packageで分ける)となっているのみでワンバイナリになる感じでしょうか?
- package でわけるのみでワンバイナリにしています。
- 外側のモジュールから、あるモジュールの公開部分だけにアクセスさせる、つまり非公開部分にアクセスしてしまわないようにするための仕組みが何かあったりしますでしょうか?
- go であれば internal/ 以下におけば他 package から読めないので非公開部分は internal/ 以下におくようにしています。
- CQRSの部分もう少し詳しく聞きたいのですが、パフォーマンスの関係上複数のモジュールに関わるテーブルからjoinして取得したい場合、この処理はどこに置いておりますか?
- そのような場合は完全な (?) module 化を諦めないといけないので、複数 module に依存した特別な module を作ってその中でやるぐらいですかね。基本的には我々は本当に必要になるまではやらないようにしています。
LT②『RDRAとDDDでGoのモジュラーモノリスアプリを設計してみた話』
株式会社ラクス 今本 光さん(@imamotohikaru)
- RDRA: リレーションシップ駆動要求分析
- 上位のレイヤーから要求分析をスタートして下位レイヤーに向けて詳細化していく
- レイヤーとは
- システム価値: 誰にとっての価値か
- システム外部環境: どのように使われるか
- システム境界: どう関わるか
- システム: そのもの
- 下位のWhyが上位レイヤになる
- 正直かなり大変ではある
- DDD
- コンテキストマップを作成して、コンテキスト間に依存
- 実装
- コンテキストマップと同じ粒度でGo Moduleを実現する
- moduleごとにレイヤードアーキテクチャ構成にする
- コンテキストごとにRDBも分割している
- GitHubに実装方針を公開している
- 前提として、新規システムをゼロから構築する際の話
- なのでDB分割の困難はなかった
- 要求分析フェーズはどれぐらいかかった?
- RDRAとDDDの設計で半年ぐらい
- 実装も含めると1年3ヶ月ぐらい
### Q&A
- 今回の対象としていたシステムの規模などをテーブル数や画面数、FP等で表現していただけないでしょうか?
- テーブル数は30程度、画面は20程度で割と小規模です。FP数は把握できていませんが、ビジネスロジックの複雑度がとても高かったのでFP数もそれなりの規模でした。
- 質問です。コンテキスト境界の理解にどのくらいかかったか知りたいです。というのも初期の頃って、ドメイン知識が浅いから、境界があいまいであったり、ころころ変わることがあるなと感じるので。
- RDRAでの要件定義の時点である程度業務全体の知識は把握できていたので、コンテキスト分割についてはRDRAの業務分類と照らし合わせて割とスムーズにできました。要件定義開始時からコンテキスト分割を一旦完了するまでは3ヶ月程度かかった記憶があります。
- 運用後のRDRAのメンテは行っていますでしょうか?
- 実はまだローンチ前なのでメンテする機会は発生していないのですが、メンテは行っていく想定です。RDRAの長所として仕様変更が発生した際の影響範囲の特定に役立つというものがあるので、積極的にメンテナンスはしていきたいです。
LT③『TypeScript・モジュラーモノリスによる複雑なWebサービス開発』
SALESCORE株式会社 成澤 克麻さん(@KatsumaNarisawa)
- なぜモジュラモノリスを選択したか
- 複雑なサービスだから。UNIX哲学にならって1つ1つのことをシンプルにやるモジュールを組み合わせるようにしたい
- どこが複雑?
- 4年ほど1人で開発していたプロダクト
- 外部サービスからのデータ取り込みが大量にある。データパイプラインが複雑
- 機能が複雑
- 設計
- 垂直分割: ドメインごとに
- 水平分割: レイヤーごとに
- どちらもやる。コアロジックを外に抽出
- 実装
- turborepoを使ったmonorepo
- 35モジュールぐらい
- フロントとバックエンドで同じコードを使いまわしている
- モジュールごとにpackage.jsonを定義
- exportする関数だけ選べる名前衝突が避けられて良い
- やってみた感想
- 思考が整理される
- モジュールを組み合わせて複雑なサービスを組み立てられる
- 依存関係を強制できる
- infraからpresentationは参照できない、など
- 凝集度が高い
- buildとlintのパフォーマンスが悪い
- 新規メンバーのキャッチアップコストには影響してない
- 違う観点だけど、monorepoであることが非常に良い
- モジュールの呼び出しは?
- npm packagesを単純にインポートして関数呼び出しするだけ
- コアロジックを外に出すというのは?
- 本当に複雑なロジックをモジュールに入れ込むのは諦めた
### Q&A
- それぞれのモジュールのAPIの型定義はそれぞれのモジュールから提供されるようになっているのでしょうか。それとも型定義用のモジュールを用意する、root リポジトリで管理するなどの方法をとっているのでしょうか。
- 型をexportする必要があれば、モジュールからexportしています!
- フロントエンドとバックエンドでドメインの関心ごとが違う場合はあるのでしょうか?その場合の分け方はどのようにしていますか?
- (僕宛ですかね?いったん回答させていただきます!)「FEとBEで関心ごとが違うから共通化すべきではない」という議論を目にしますが、個人的な体感としてはあまりピンときていません。ドメインのロジックを書いているのであれば、そこにFE/BEという視点は入り込まない気がしています!(ご質問ありがとうございます!)
LT④『マイクロサービスではなくモジュラモノリスを採用した理由』
株式会社プラハ 粟田 恭介さん(@wooootack)
- 背景
- 8年ぶんの負債があることはわかっていたので新機能を新システムへ
- 最初はマイクロサービスをやろうとしていたが撤退
- 今の社内のチームには合わない
- モジュール間を疎結合にするため、シナリオ層を設けている
- サービス層とかユースケース層と同じイメージ。順番にモジュールを呼んでいくだけ
- シナリオ層は詳細には立ち入らない
- マイクロサービスは将来的にありうる
- サービス境界の探索を、モジュール境界として実験できる
- マイクロサービスにする前にモジュールごとにDB分割することもできる
### Q&A
- どのくらいの組織規模ならマイクロサービスをやってもいいかなと判断しますか?
- 粟田 恭介 12:51
抽象的な回答としては、各サービスを開発できるチーム、インフラ専任チーム、共通処理選任チームが用意できるだと思います!
- 特にインフラはIaCで構築しておかないと地獄を見そうなので、ある程度強いインフラチームは必須だというのが自分の感覚です。具体的な数値をちょっと出せずすみません)
- シナリオ層という表現にした背景知りたいです!
モジュールを組み立ててロジックを表現するなら、ユースケースという表現が近いのかなと思い。
- 粟田 恭介 12:53
1つはユースケース層は各モジュールの中で使われていた名前だったため、別の命名を探していたというのが背景にあります。
あとはマイクロサービスにおけるSagaパターンのオーケストレータ的な立ち位置であることも意識しているため、ユースケースよりもより上位であると考えていて、あえて別の名前をつけることにしました。
LT⑤『(仮)モノリスとマイクロサービスを経てモジュラモノリスを導入した実践事例』
アソビュー株式会社 兼平 大資さん(@disc99_)
- VPoE兼テックリード
- 導入の経緯
- モジュラモノリス期は3年ぐらい
- 会社と組織の状況
- Java x Spring Boot
- 起動モードによってローカルではモノリス、リモートではマイクロサービスのように風うるまうことができる
- モジュール境界
- モノリスに比べてスピード感が欠けるシーンもある
- 関連する議論
### Q&A
- 組織はあっさり変わったりもするがシステムをすぐに変更するのはできない - 組織が変わったとしても対応できるようなシステム構成を意識している