Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
proposed |
@grzesiek
@fabiopitino
| 2023-05-22 |
GitLab モジュラーモノリス
要約
GitLab Railsプロジェクトのメインは、Ruby on Railsフレームワークを使った大規模なモノリシックアプリケーションとして実装されています。220万行以上のRubyコードがあり、毎日何百人ものエンジニアが貢献しています。
アプリケーションは10年以上にわたって複雑さを増しています。モノリシックアーキテクチャは、この間、高い開発速度と優れたエンジニアリング生産性を維持することを可能にし、私たちに役立ってきました。
私たちはアプローチしやすいオープンコアアーキテクチャを持つように努力していますが、開発速度を維持し、開発の予測可能性を高めるためには、ドメイン間の境界を強化する必要があります。
エンジニアリング組織として成長するにつれて、私たちは少し異なる、しかし関連するアーキテクチャパラダイムを探求したいと考えています。それは、サテライトサービスを備えたモノリシックアーキテクチャを使用しながらも、モジュラーモノリス設計です。
これにより、エンジニアリングの効率を高め、認知的な負荷を減らし、最終的には内部コンポーネントを切り離し、必要に応じて個別にデプロイして実行できるようにしたいと考えています。
動機
大規模で緊密に結合したモノリシックなアプリケーションで作業することは困難です:
エンジニアリング
- エンジニアのオンボーディングには時間がかかります。エンジニアが生産性を感じられるようになるまでには、コンテキストの大きさと結合の多さから、しばらく時間がかかります。
- いくつかのドメインで
CODEOWNERS
ファイル機能を使用する必要がありますが、これらのルールは複雑です。 - アプリケーションの規模が大きいため、エンジニアがアプリケーションのメンタルマップを構築するのは困難です。一見孤立した変更であっても、モノリスの他の部分に広範囲に影響を及ぼす可能性があります。
- エンジニアの人材の減少/維持。生産性を妨げる障害に常に対処することは、エンジニアにとって疲労であり、士気を低下させます。
アーキテクチャ:
- モノリス内部の構造はほとんどありません。私たちは、いくつかのモジュールの作成を強制しようとしていますが、モノリスの機能部分がどうあるべきか、コードがどのように構成されるべきかについての全社的な戦略はありません。
- 既存のモジュール間の分離はありません。Rubyには、効果的に境界を強制するためのツールがすぐに使える状態で提供されていません。すべてが同じメモリ空間の下にあります。
- 私たちは、効率を高める抽象化をほとんど構築しません。
- アプリケーションの安定した部分を別のサービスに移動することは、高いカップリングのために不可能です。
- 特定のドメインに個別に変更をデプロイすることも、そのドメイン内部で起きている障害を切り分けることもできません。
生産性:
- 複雑な変更に対する高い生産時間中央値。
- より広いコミュニティのメンバーが貢献するのは無理があります。
- テスト時間の短縮には、勤勉で粘り強い努力が必要です。
目標
- 懸念事項の分離による開発速度と予測可能性の向上。
- 結合を減らし、有用な抽象化を導入することで、コード品質を向上させます。
- GitLabコンポーネントを個別にデプロイして実行するために必要な抽象化を構築します。
どうすればいい?
モジュール化が重要な技術的努力であることは認識していますが、主な課題は技術的なことよりもむしろ組織的なことだと考えています。私たちは、GitLab.comだけでなくセルフマネージド・インスタンスでもうまく機能する実用的な方法でモジュールが分離されるように分離を設計する必要があるだけでなく、モジュール化をGitLabで働きたい方法と一致させる必要があります。
私たちのモノリスのモジュール化を成功させるには、多くの側面と詳細が必要です。私たちは以下に挙げるような側面に取り組み、それらを洗練させ、目標に向かって前進する中でさらに重要な詳細を追加していきます:
- 重要なインサイトを提供するモジュール化の概念実証を提供します。
- バウンデッドコンテキストを定義することにより、モジュール化計画を組織構造に整合させます。
- 組織構造を反映したモジュールへのドメイン分割(TODO)
- 分離されたドメインでの作業方法について、チームメンバー向けのトレーニングプログラムを開始します。(TODO)
- 制御の逆転により、非結合ドメインの構築を容易にするツールの構築(TODO)
- モノリス内の六角形アーキテクチャの導入
- 一方向依存とホストアプリケーションによるクリーンアーキテクチャの導入(TODO)
- ドメインの実行とデプロイを別々に行えるようにする抽象化機能の構築(TODO)
ステータス
進行中
用語解説
-
modules
はRubyモジュールで、コードを階層的にネストするために使用できます。 -
namespaces
はRuby定数のユニークな階層です。たとえば、Ci::
だけでなく、Ci::JobArtifacts::
やCi::Pipeline::Chain::
もあります。 -
packages
は、関連する機能をグループ化したPackwerkパッケージです。これらのパッケージは、設計やアーキテクチャによって大きくなったり小さくなったりします。パッケージの中では、すべての定数(クラスとモジュール)は同じ名前空間を持ちます。例えば- パッケージ
ci
では、すべてのクラスはCi::
名前空間の下に入れ子になります。Ci::PipelineProcessing::
のように、入れ子になった名前空間を持つこともできます。 -
ci-pipeline_creation
Ci::PipelineCreation::Chain::Command
パッケージでは、すべてのクラスはCi::PipelineCreation
の下にネストされます。 - パッケージ
ci
では、MergeRequests::UpdateHeadPipelineService
という名前のクラスは、パッケージの名前空間と一致しないため、許可されません。 - これはPackwerkのRubocop Copsを使えば簡単に実行できます。
- パッケージ
-
bounded context
はトップレベルのPackwerkパッケージで、ドメインのマクロ的な側面を表します。例えばCi::
MergeRequests::
,Packages::
, など。- 境界コンテキストは、単一のRubyモジュール/名前空間によって表されます。例えば、
Ci::JobArtifacts::
ではなくCi::
です。 - 境界コンテキストは、1つまたは複数のPackwerkパッケージで構成することができます。ドメインが非常に複雑で、すべての実装の詳細の間でプライバシーを強制したい場合は、入れ子のパッケージが推奨されます。例えば、
Ci::PipelineProcessing::
とCi::PipelineCreation::
は、同じバウンデッドコンテキストの別々のパッケージとして、実装の詳細を非公開にしたまま公開APIを公開することができます。 -
RemoteDevelopment::
のような新しいバウンデッドコンテキストは単一のパッケージで表現できますが、Ci::
のような大きく複雑なバウンデッドコンテキストは、より小さい/入れ子のパッケージに編成する必要があります。
- 境界コンテキストは、単一のRubyモジュール/名前空間によって表されます。例えば、