Content last updated 2026-06-15

Rails モノリスの分解

This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
StatusAuthorsCoachDRIsOwning StageCreated
proposedgrzesiek fabiopitino ayufan2023-05-22

概要

メインの GitLab Rails プロジェクトは、Ruby on Rails フレームワークを使用する大規模なモノリシックアプリケーションとして実装されています。220 万行以上の Ruby コードを持ち、何百人ものエンジニアが毎日コントリビュートしています。

このアプリケーションは 10 年以上にわたって複雑さが増しています。この間、モノリシックアーキテクチャは高い開発速度と優れたエンジニアリング生産性を維持することを可能にし、私たちに大きく貢献してきました。

アプローチしやすいオープンコアアーキテクチャを目指しつつも、速度を維持し開発の予測可能性を高めるために、ドメイン間の境界を強化する必要があります。

フロントエンドにも同じことが言えます。Web UI は、大規模で密結合な JavaScript と Vue のコードベースであり、単一の Webpack バンドルとしてビルドされ出荷されています。これはモノリスと同じ運命を共有しています。すべてが一緒にコンパイル、デプロイ、リリースされ、UI の一領域だけを他と独立して進化させたり出荷したりする方法がありません。そのため、分解には 2 つの補完的なトラックがあります。Rails アプリケーションをモジュール化する バックエンド トラックと、ビルドパイプラインと UI をモジュール化する フロントエンド トラックです。どちらも以下で説明する同じ目標と原則を共有します。

なぜ今か: エージェント型への必然性

ソフトウェアの作られ方は変化しています。エージェント型 AI によって、Issue が作成されるとすぐにエージェントが作業を引き受け、コードベースの明確に定義された領域内で独立して動作し、MR を開く前に自分の作業を検証できるようになると、可能なことが変わります。これを実現するには、モジュールに明確な境界、明示的な契約、そしてビルドや実行方法に組み込まれた暗黙知がないことが必要です。

モノリスは、何年ものコンテキストを頭の中に持つ人間の開発者向けに作られました。エージェントにはそのようなコンテキストがありません。依存関係が暗黙的で、安全に作業するために必要な知識がすべてリポジトリ内に存在しているわけではないため、全体を推論せずに 1 つの領域を安全に変更することはできません。モジュール境界は、コードベースのある領域をエージェント、そして人間が単独で推論できるほど小さくします。

これはモジュール化の位置づけを変えます。もはやエンジニアリング速度や認知負荷だけの話ではありません。大規模なエージェント型開発のための構造的な前提条件です。明確な契約、自己完結したコンテキスト、高いテストカバレッジを持つモジュールは、エージェントが自律的に作業でき、修正がより早くお客様に届き、チームがモノリスの結合に引きずられず自分たちのペースで進める場所になります。

目指しているもの

私たちは、サテライトサービスを持つモノリシックアーキテクチャを引き続き使用しながら、モジュラーモノリスデザインへ進化させたいと考えています。また、投資に見合うモジュールについては、GitLab.com、Dedicated、セルフマネージドインスタンス上で、単一の契約に対してモノリスと統合される、独立してデプロイ可能な単位へ進めたいと考えています。

これにより、エンジニアリング効率を高め、認知負荷を軽減し、コードベースを AI エージェントが読み解けるものにし、最終的には投資対効果が明確な場合に別々にデプロイ・実行できる程度まで内部コンポーネントを切り離せるようになるはずです。

フロントエンドでは、これは独立してビルド・デプロイ可能な UI モジュールが、共有シェルアプリケーションと明示的なモジュール契約を通じて統合されることを意味します。これは、バックエンドのバウンデッドコンテキストとパブリックインターフェイスに対応する視覚的な対応物です。

動機

大規模で密結合なモノリシックアプリケーションを扱うことは困難です:

エンジニアリング:

  • エンジニアのオンボーディングに時間がかかります。コンテキストの規模と結合の量により、エンジニアが生産的だと感じるまでに時間がかかります。
  • いくつかのドメインに CODEOWNERS ファイル機能を使用する必要がありますが、これらのルールは複雑です
  • アプリケーションの規模が大きいため、エンジニアがアプリケーションのメンタルマップを構築することは困難です。一見分離されている変更でさえ、モノリスの他の部分に広範な影響を及ぼす可能性があります。
  • エンジニアリング人材の離職と定着。生産性への障壁と絶えず向き合うことは、エンジニアにとって疲弊し士気を下げるものです。

アーキテクチャ:

  • モノリスの内部にはほとんど構造がありません。いくつかのモジュールの作成を強制しようとしてきましたが、モノリスの機能的な部分がどうあるべきか、コードをどのように整理すべきかについて、全社的な戦略はありません。
  • 既存のモジュール間に分離がありません。Ruby は境界を効果的に強制するための組み込みツールを提供していません。すべてが同じメモリ空間の下に存在します。
  • 効率を高める抽象化を構築することはほとんどありません。
  • 境界はデータベースについて何も語っていません。一見分離されているドメインでさえテーブルを共有し、境界をまたぐ外部キーを持ち、境界線を越える ORM 関連を維持しています。抽出を実際に妨げるのはデータ結合です。
  • 高い結合のため、アプリケーションの安定した部分を別サービスに移すことができません。
  • 特定ドメインへの変更を個別にデプロイし、その中で発生している障害を分離することができません。

エージェント型 AI:

  • エージェントには暗黙のコンテキストがありません。依存関係が暗黙的で変更の影響範囲が不明確なため、全体を推論せずに 1 つの領域を安全に変更することはできません。
  • ドメインで作業するために必要な知識、つまり境界、契約、不変条件、runbook が、すべてリポジトリ内に存在しているわけではありません。
  • 明確な境界と自己完結したコンテキストがなければ、エージェントは人間が暗黙知を補わずに Issue を引き受け、変更を行い、検証し、MR を開くことができません。

顧客価値:

  • セルフマネージドおよび Dedicated のお客様は、アップグレードするまで修正を見ることができず、それが数か月後になることもあります。モノリス全体のリリースを出荷せずに、単一の機能領域に対して対象を絞った修正をロールアウトすることはできません。
  • 1 つのドメインの障害がアプリケーション全体を劣化させる可能性があり、負荷の高いドメインを他から独立してスケールさせることもできません。独立したモジュールは別々にスケールし分離できるため、信頼性とフォールトトレランスが向上します。

生産性:

  • 複雑な変更の本番環境到達までの中央値が長い。
  • より広いコミュニティメンバーにとって、コントリビュートは圧倒されるものになる場合があります。
  • テスト時間の削減には、勤勉で粘り強い取り組みが必要です。

目標

  • 関心の分離により、開発速度と予測可能性を高める。
  • 結合を減らし有用な抽象化を導入することで、コード品質を改善する。
  • モジュールをエージェント対応にする。明確な境界、明示的な契約、そしてエージェントが自律的に作業するために必要なすべてのコンテキストをリポジトリにコミットする。
  • 依存関係を明示的にし、強制する。宣言されていない依存関係は存在しません。裏口から結合を再作成することはできません。
  • 広くモジュール化し、選択的に抽出する。ほとんどのコードはモノリス内でそのままモジュール化されます。ROI が明確な場合にのみ、モジュールを別々にデプロイされるサービスへ抽出します。
  • 抽出が正当化される場合に、そのコストを安くする抽象化を構築する。データ所有、独立した運用性、独立したデプロイにより、修正がモノリス全体のリリースなしでお客様に届くようにします。

バックエンド分解

バックエンドトラックでは、GitLab Rails アプリケーションを、明示的かつ強制された境界を持つバウンデッドコンテキストへモジュール化し、独立して運用可能で、ROI が明確な場合には独立してデプロイ可能なドメインを目指します。

どのように実現するか?

モジュール化が重要な技術的な取り組みであることは認識していますが、主な課題は技術的なものではなく組織的なものだと考えています。モジュールが実用的な方法で切り離されるように分離を設計するだけでなく、GitLab での働き方に沿ってモジュール化を整合させる必要があります。

モノリスのモジュール化を成功させるためには、多くの側面と詳細が必要です。以下にリストされた側面に取り組み、それらを洗練させ、目標に向けて進みながらさらに重要な詳細を追加していきます:

  1. 主要な洞察をもたらすモジュール化のプルーフオブコンセプトを提供する
  2. バウンデッドコンテキストを定義することにより、モジュール化計画をプロダクト構造に整合させる。
  3. 横断的ライブラリを gem に抽出するlib//ee/lib からプラットフォームコードを取り出します。価値は抽出パターン、ツール、強制された分離にあり、CI 時間の削減ではありません。
  4. トランスポート層をアダプターへ分解する。Web、REST、GraphQL、Sidekiq の各トランスポートを分離し、それぞれがドメイン層のみに依存するようにします。これにより、API のみ、または Sidekiq のみのノードのようなランタイムプロファイルが可能になります。
  5. ドメイン層を分離することで、各ドメインが自身のデータを所有し、パブリック API を通じてのみ到達されるようにする。
  6. 切り離されたドメインを扱う方法について、チームメンバー向けのトレーニングプログラムを開始する(TODO)
  7. 制御の反転によって切り離されたドメインを構築しやすくするツールを構築する(TODO)
  8. モノリス内に六角形アーキテクチャを導入する
  9. 一方向依存関係とホストアプリケーションによるクリーンアーキテクチャを導入する(TODO)
  10. ドメインを別々に実行・デプロイできるようにする抽象化を構築する(TODO)

決定

  1. ADR-001: アプリケーションドメインのモジュール化? アプリケーションドメインとインフラストラクチャコードのモジュール化から始める。
  2. ADR-002: 機能カテゴリを中心にバウンデッドコンテキストを定義する。コード内の SSoT として。
  3. ADR-003: すべてのモジュールとライブラリにスチュワードを割り当てる
  4. ADR-004: 横断的ライブラリを gem に抽出する

用語集

  • 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:: のような大規模で複雑なバウンデッドコンテキストは、より小さな/ネストされたパッケージに編成する必要があります。

フロントエンド分解

目標は、独立してビルド可能な UI モジュールが共有シェルアプリケーションと明示的なモジュール契約を通じて統合される、モジュラーなフロントエンドです。これはバックエンドのバウンデッドコンテキストとパブリックインターフェイスを反映します。

フロントエンドのワークストリームは次のとおりです:

  1. ビルドパイプラインをモダナイズする。独立したフロントエンドモジュールのデプロイを可能にします。
  2. Webpack 4 から Webpack 5 / Vite へ移行する。また、これによって可能になる Vue 3 移行を完了します。
  3. モジュール契約を定義する。モジュール境界をまたいだ認可、ユーザーコンテキスト、フィーチャーフラグを管理します。
  4. 支援インフラストラクチャを構築する。シェルアプリケーション、モジュールレジストリ、Context provider API です。
  5. “Frontend LabKit” を作成する。共有ライブラリを標準化し、モジュール間で一貫したユーザー体験を確保します。

詳細な設計については、フロントエンド分解 を参照してください。

参考資料

参考資料のリスト


フロントエンド分解
概要 GitLab フロントエンドは、同時にビルドされる複数の Webpack バンドルとして構築・出荷されています。このトラックでは、UI モジュールを独立して開発、ビルド、テスト、デプロイできるよ …
ドメイン層を分離する
このページは、六角形モノリスの中核にあるビジネスロジックである アプリケーションドメイン を、境界付けられ、独立して所有されるモジュールへ分離するための単一の情報源です。 ここで扱うのはドメインコード …
トランスポート層をアダプターへ分解する
トランスポート層とは何か? トランスポート層は、六角形モノリスがアダプターと呼ぶものです。つまり、外部世界をドメインのパブリックインターフェイスへ接続する、ポートとアダプターのアーキテクチャの外側の層 …
バウンデッドコンテキストの定義
歴史的なコンテキスト 2024 年 5 月まで、GitLab のコードベースには明確なドメイン構造がありませんでした。 最初のステップとしていくつかのモジュールの作成を強制しましたが、一貫して実施する …
横断的ライブラリを gem に抽出する
GitLab が横断的で ActiveRecord 非依存のプラットフォームライブラリを lib/ と ee/lib から gems/ 配下の Ruby gem へ抽出する方法と理由。
六角形 Rails モノリス
背景 このデザインドキュメントは、以前の Composable GitLab Codebase に取って代わります。以前は、コードベースを技術的なランタイムプロファイルに分離するというアイデア、例えば …
バックエンド分解 ADR 004: 横断的ライブラリを gem に抽出する
コンテキスト ADR-001 は、今日では主に lib/ と ee/lib に存在する技術的で横断的なコードである「プラットフォーム」層を、gem として抽出された独立したライブラリへ分解できることを …
モジュラーモノリス ADR 001: アプリケーションドメインのモジュール化
コンテキスト コードベースをモジュール化する前に、まずどのように分割するかを定義する必要がありました。 決定 最初に、アプリケーションアダプター(Web コントローラーとビ …
モジュラーモノリス ADR 003: モジュールのスチュワードシップ
コンテキスト ドメインとプラットフォーム層にスチュワードシップをどのように割り当てるか?コードのその部分に対してビジョンと方向性を提供できる明示的なスチュワードがいない共有コードが大量に存在します。 …
モジュラーモノリス ADR 002: 境界付けられたコンテキストの定義
コンテキスト アプリケーションドメインを中心に据えて、どのようにモジュール化するかを定義する必要がありました。 決定事項 アプリケーションドメインは、GitLab アプリケーションのトップレベルモジ …
参考資料
関連するデザインドキュメント Composable Codebase デザインドキュメント 関連 Issue GitLab モノリスをコンポーネントに分割する 「分離されたサービス」のビルドと使用を簡 …
ドメインモジュールをパッケージに変換する
既存のコードをモジュール化にリファクタリングする一般的な手順は以下のとおりです: 同じ 境界付けられたコンテキスト に関連するすべてのクラスとモジュールに同じ名前空間を使用します。 なぜ? コードベー …
モジュラーモノリス: PoC
モノリスのモジュール化は複雑なプロジェクトです。多くの未知の要素が存在します。リスクを軽減し、重要な知見を得るために役立つのが、早期に実施できるプルーフオブコンセプト(PoC)です。これにより、何を行 …