はじめに
こんにちは、GLOPLAチームエンジニアのnyagaoです
私たちGLOPLAチームは現在Large-Scale Scrum (LeSS)を採用しており1つのスクラムチームにエンジニアが4人ずつ所属する形で、計5つのチームが活動しています。
各チームは大きなepicに沿って開発を進めていますが、明確な担当領域は決めず、タスクの進捗状況や重要度に応じて流動的にテーマを切り替えながら進めています。
背景
現在、2021年5月にリリースされたGLOPLA LMSは機能を拡充しながら成長を続けています。
また、LMSを基盤とした新規プロダクトも現在開発中でありこれらのサービスはすべて1つのリポジトリ(Monorepo)で管理されています。
また、アプリケーションの全ての機能を単一のプロジェクトで動かしているモノリス(モノリシックアーキテクチャ)を採用しています
新規プロダクト立ち上げ当初は、LMSのサーバー構成や共通部品をそのまま活用することで開発効率を最大化しようとしていました。しかし、現在以下のような課題が浮き彫りになってきました。
- 共通化した部分で問題が発生しやすくなった
- 将来的にプロダクトが増える場合、さらなる課題が予測される
- マルチプロダクト展開を見据えて認証を切り出したりマイクロサービス等の未来を検討し始める時期に来ている
こうした背景から、現在のモノリスを見直し、将来に向けた最適な形を模索することにしました。本記事では、この取り組みの軌跡を共有します。
モノリスの課題
一般的な課題
モノリスでよく指摘されるデメリットには以下があります:
- CIの待ち時間が長い
- デプロイに時間がかかる
- コードリーディングが難しい
- スケーラビリティが低い
- トラブルシューティングに時間を要する
- モニタリングやロギングの運用コストが高い
チーム内での具体的な課題
私たちのチームでも、以下のような問題が発生しています:
- 5チームが同一リポジトリを修正するため、影響範囲の競合が頻発
- 上記により、同時に進められないユーザーストーリーが発生し、待機状態が増える
- サービス間の切り替えや意図しないコードの影響で、開発者体験が悪化
- 一方の改修が他方に影響する際、確認作業が多発し、差分やバグが生まれる
- 別サービスの仕様に引っ張られ、独自仕様や冗長な分岐処理が増加
- 共通ライブラリのアップデート時に影響範囲の特定が困難
- サービス間で型の整合性を取るためにコードが複雑化(魔改造)
将来的な懸念
- サービスが増えた時の障害影響範囲が爆大
- サービスが増えた時の改修コストが爆大
- データ管理の複雑性
上記のように今後開発を進めていくと必ずボトルネックになるものがありそうだとエンジニア内では認識が取れました
モノリスのメリット
課題が多い一方で、初期の開発では以下のような利点を享受しました:
- 既存インフラをそのまま活用
- 共通機能を流用可能(例:ユーザー管理、メール送信、IP制限)
- 既存チームが先行実装した共通部品を使用可能
- 学習コストが低い:構成が統一されているため、チーム間の移動が容易
- デザインガイドラインを統一しやすい
しかし、長期的な視点では課題が明確になったため、将来に向けてどのようにリポジトリ構造を進化させるか検討を始めました。
今後の方向性
現在、既存サービスと新サービスを即座に分離するのではなく、共通機能の疎結合化を目指しています。
以下はチームで議論した、切り出し候補の具体例です
最終目標としては、PO(プロダクトオーナー)が開発ロードマップにリアーキテクチャを載せられる状態にすることを目指しています。
プラン | プランA 認証基盤を切り出す |
プランB ユーザー管理を切り出す |
プランC 2つのサービスを同一テナントで運用可能にする |
---|---|---|---|
ビジネスインパクト |
Pros: 新規サービスでメアド認証・外部認証・社員番号認証が可能 Cons: 独自認証方式の追加や変更が困難 |
Pros: すべてのサービスでユーザー属性情報の参照・更新が可能 新規サービスで一括ユーザー管理機能が使用可能 Cons: LMS以外でもユーザー管理が必要になり煩雑 権限の再考が必要 |
Pros: 1テナントで両サービスの利用が可能 Cons: 新規サービスリリース時に追加対応が必要 同一ユーザーの権限管理が複雑化 |
技術的影響 |
Pros: 認証機能の共通化でコスト削減・保守性向上 リリース作業の分離が可能 認証トラフィック増加時も本体に影響なし Cons: モノレポをやめた場合、ローカル開発の難易度増 ライブラリアップデートのコスト増 |
Pros: ユーザー管理機能の共通化でコスト削減・保守性向上 個人情報の保護強化が可能 Cons: 高頻度アクセスに対応するための可用性の高い設計が必要 モノレポをやめた場合の課題(ローカル開発難度増など) |
Pros: 比較的容易な対応で実現可能 Cons: パッチワーク的対応のためスケールが難しい |
実装規模感 | 中程度 | 大規模 | 小規模 |
現在では上記のプランを提案し、ビジネスインパクト、技術的影響のProsCons、実装規模の観点からプランAが最有力として進んでいます
プランBは工数が非常に多いことに加え、新規サービスと既存サービスでユーザー管理の定義が異なるため、初手で取り組むにはリスクが高いと判断しました。そのため、このプランは将来的に必要になる場合を見据え、現時点では見送る方針です。
一方、プランCは実装規模自体は小さいものの、現状では実施しても将来的にプランAおよびプランBを実施する必要があるため、非効率と判断し採用を見送りました。
今後
現時点で決定しているのは、プランAを実施することのみです。本記事では、その実装手段について、筆者個人の見解を基に考察を共有します。(あくまで個人の見解です)
Modular Monolith
現在のMonorepo構造を維持しつつ、Modular Monolithとしてモジュールごとにコードを分割・疎結合化する方針が最有力候補です。このアプローチにより、アプリケーションやデプロイをモジュール単位で管理できるようにすることを目指します。
また、Modular Monolith化の後に必要であればマイクロサービス化に移行する選択肢も残されており、柔軟性が高い点が特徴です。具体的には、以下の順序で疎結合化を進める計画です:
- 認証基盤の分離
- ユーザー管理機能の分離
- 既存サービスおよび新規サービスの分離
実験::Packwerkによる依存関係の可視化
依存関係の現状を把握するために、packwerkを試しました
- Gemfileに追加
gem 'packwerk'
- Gemをインストール
$ bundle install
- 設定ファイルを生成
$ bin/packwerk init
- 実行!
$ bin/packwerk check
これで全てうまくいく…!
📦 Packwerk is inspecting 4200 files
📦 Packwerk is inspecting 4200 files
ドキドキ!
と思っていたのですが
以下のエラーが発生しました:
Ambiguous constant definition: (ConstantResolver::Error)
原因は、複数のサービスが同一レポジトリ内に存在し、同名のファイルが多数あるため、どの定義を参照すべきかPackwerkが判別できないことにあります。この問題を解決するには、大掃除を行うか、モジュール化を手動で進めながら対処する必要があります。どちらが早いかは現時点で未知数ですが、来年には状況が改善していることを期待しています。
【番外編】マイクロサービス化の難しさ
当初、サービスの分離は「マイクロサービス化=レポジトリの分割」と単純に考えていました。しかし、弊社の優秀なSREチームとのディスカッションにより、以下の課題が浮き彫りになりました:
高コスト(設計や運用、データストア構築など)
チーム間連携の複雑化
これらの理由から、初手でのマイクロサービス化は避け、十分な準備が整った段階での検討が適切だと考えています。
【番外編】 レポジトリのクローン案
今あるレポジトリまるっとコピーしていらないもの削ぎ落とせばええやんええやんなんかおもろそうやん
の考え方で爆誕した思想
しかし、以下の理由から現実的ではないと判断しています:
- インフラコストの増加
- 外部サービスの重複管理
- 設定や運用の負担倍増
この方法は、緊急時以外では推奨できません。
最後に
2025年、GLOPLAチームは単純なモノ構造から卒業する予定です。アーキテクチャ設計やリアーキテクチャに関する知見をお持ちの方、または経験を積みたい方の応募をお待ちしております!
GLOBISで一緒に働く仲間を募集しています!
GLOBISの開発組織では、一緒に働けるエンジニアを探しています!
まずは、カジュアル面談を通して、あなたに合う組織かどうか確かめてみませんか?