Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
proposed |
@fabiopitino
| 2023-06-21 |
境界のあるコンテキストの定義
現状
今日、GitLabのコードベースは明確なドメイン構造を持っていません。最初のステップとしていくつかのモジュールを強制的に作成しましたが、それを一貫して行うための明確な戦略がありません。
コードの大部分は適切に名前空間化されておらず、整理されていません:
- 使用されているRuby名前空間は必ずしもSSoTを表していません。重複する概念が複数の名前空間にまたがっています。例えば:
Abuse::
とSpam::
やSecurity::Orchestration::
とSecurity::SecurityOrchestration
。 - 同じ境界コンテキストに関連するドメインコードが複数のディレクトリに散らばっています。
- ドメイン・コードは、
app/
の同じドメインとは異なる名前空間の下、lib/
ディレクトリに存在します。 - ある名前空間は非常に浅く、少数のクラスしかコンテナを持っていませんが、他の名前空間は非常に深く、大規模です。
- 古いコードの多くは名前空間化されていないため、使用されているコンテキストを理解するのが難しくなっています。
ゴール
- バインドされたコンテキストが持つべき特性のリストを定義します。例:少なくとも1つの製品カテゴリーに関連する必要があります。
- すべてのドメインコードが分解される、トップレベルの境界付きコンテキストのリスト。
- エンジニアは利用可能なバウンデッド・コンテキストのリストを明確に見ることができ、新しいクラスやモジュールを追加する場所を簡単に決めることができます。
- 新しいバウンデッド・コンテキストをアプリケーションに追加するプロセスを定義します。新しいバウンデッド・コンテキストは、以前に定義した特性を守る必要があります。
- 作成者以外の新しいトップレベル名前空間を使用できないように、バインドされたコンテキストのリストを強制します。
イテレーション
0.コードベースからライブラリを抽出
2023年6月、メインコードベースからgemsを取り出し、monorepo](https://gitlab.com/gitlab-org/gitlab/-/blob/4c6e120069abe751d3128c05ade45ea749a033df/doc/development/gems.md) 内の[gems/
ディレクトリへの展開を開始しました。
これはモジュール化への第一歩です。
- 汎用コードとドメインコード(ビジネスロジックを動かすコード)を分離したいのです。
- 一般的なコードから
lib/
ディレクトリをクリーンアップしたいです。 - ドメインコードに依存しないように、別のプロジェクトに住むコードを分離したいのです。
これらのgemはまだmonorepoの一部ですが、必要に応じて専用のリポジトリに抽出することができます。
gemsの抽出はモジュール化の妨げにはなりませんが、lib/
、汎用的なコードが少ないほど、境界のあるコンテキストの識別と分離が容易になります。
1.バウンデッドコンテキストとは?
Proposal: split GitLab monolith into componentsの研究から、ガイドラインとしてプロダクトカテゴリーに従うことは、組織構造をフォルダ構造(例えば、app/modules/verify/pipeline-execution/...
)に変換するよりもずっと良いようです。
しかし、このガイドラインだけでは不十分で、より具体的な戦略が必要です:
- 商品カテゴリーは所有者が変わる可能性があり、私たちはかなり頻繁な変更を見てきました。商品カテゴリの所有者が変わるたびにコードを移動するのは、メンテナンスのオーバーヘッドが多すぎます。
- チームや組織の変更は、特定のモジュールの所有者を変更することだけを意味します。
- バウンデッドコンテキスト(トップレベルのモジュール)は、実装の詳細をカプセル化し、より小さなインターフェイスを提供するために十分に深いものであるべきです。
- Browser Performance Testingのようないくつかの製品カテゴリーは、それだけでバウンデッドコンテキストを表現するには小さすぎます。意味のあるときには、製品カテゴリをグループ化する戦略を持つべきです。
-
Category:Pipeline Composition
やCategory:Continuous Integration
は、パイプライン作成チームとパイプライン実行チームが多くのコードを共有している例です。 - コードの一部には、明確な製品カテゴリが関連付けられていないかもしれません。
上記にもかかわらず、製品カテゴリは、アプリケーションで使用されている境界のあるコンテキストの大まかなビューを提供します。
1つのアイデアは、製品カテゴリを使用して、束縛されたコンテキストの初期セットをスケッチすることです。次に、関連する、または強く結合されたカテゴリを同じ束縛されたコンテキスト の下にグループ化し、不足する場合は新しい束縛されたコンテキストを作成します。
2.既存の境界付きコンテキストを識別
まず、スプレッドシートにすべてのRubyファイルをリストアップし、上記のガイドラインに従ってコンポーネントに分類します。Ci::、Packages::など、すでにかなり明確になっているものもあります。コンポーネントは既存の命名ガイドに従ってください。
これは、各DevOpsステージの代表的なメンバー(例えば、Senior+エンジニア)からなる短期間のワーキンググループになる可能性があります。WGはハイレベルなコンポーネントの定義を支援し、それぞれのDevOpsステージの変更を推進するためのDRIとなるでしょう。
3.境界コンテキストのリストの公開
コードベースから抽出したバインドされたコンテキスト(トップレベルの名前空間)のリストは、プログラムで使用できるように静的に定義する必要があります。
# file: config/bounded_contexts.yml
bounded_contexts:
continuous_integration:
dir: modules/ci
namespace: 'Ci::'
packages: ...
merge_requests: ...
git: ...
この静的リストがあれば
- エンジニアが全体像を把握できるように、既存の境界コンテキストを文書化します。
- 新しいクラスやモジュールを配置する場所を理解します。
- 束縛されたコンテキストのリストにないトップレベルの名前空間が使用されている場合は、それを強制します。
- 指定されたリストに基づいて非標準のRailsディレクトリを自動ロードします。