前置き
アプリケーションアーキテクチャの進化と、それを支え、時には先行して進化するCI/CDパイプラインアーキテクチャの変遷を、ステップバイステップで詳細に解説していきます。
このプロセスは、
「アーキテクチャの変更を可能にするために、まずパイプラインという“足場”から組み替える」
という、非常に戦略的な流れを辿ります。
フェーズ1:シンプルなモノリシック・パイプライン
この段階は、すべてのロジックが1つのリポジトリ、1つのデプロイ可能な成果物(モノリス)にまとめられている状態です。
アプリケーションアーキテクチャ
シンプルなモノリス
単一のリポジトリ、単一のビルドプロセス、単一のデプロイ成果物。
CI/CDパイプラインアーキテクチャ
一本の線形パイプライン。
1つのコミットが、すべてのプロセスを直列にトリガーします。
graph TD
A[Commit] --> B[Build (App)];
B --> C[Unit Test (All)];
C --> D[Integration Test (All)];
D --> E[Security Scan (All)];
E --> F[Deploy to Staging];
F --> G[Deploy to Production];
顕在化する「痛み」(次のフェーズへのトリガー)
Four Keysの悪化
・変更のリードタイム(LT)が壊滅的に悪化
アプリが巨大化するにつれ、C[Unit Test (All)] や D[Integration Test (All)]の実行時間が数十分に及び、パイプラインがデリバリーの最大のボトルネックになります。
・デプロイの頻度(DF)が低下
1行の変更でも全テストが走るため、開発者はデプロイをためらうようになります。
課題
この遅いフィードバックループの中では、安全にモノリスをリファクタリング(モジュラーモノリス化)することすら困難です。
フェーズ2:ファンイン・パイプラインへの進化
このフェーズの目的は、
「アプリケーション本体のリファクタリング(モジュラーモノリス化)を安全かつ高速に行うための“足場”を、先にパイプライン側で構築すること」
です。
ステップ2.1: パイプラインの「ファンアウト」リファクタリング(ECRSの適用)
まず、モノリスを論理的なモジュール
(例: Module-Order, Module-Customer, Module-Payment)に分割することを想定します。
集約の境界をモジュール境界が分断するような設計だけはやめてください。
次に、既存の一本線形パイプラインをリファクタリングします。
ECRSのR (Rearrange) と C (Combine) を適用
C[Unit Test (All)] という単一の巨大なモノリスのテストステップを、モジュールごとの小さなテストステップに分割 (Divide) し、それらを並列 (Parallel) で実行できるように順序変更 (Rearrange) します。
ステップ2.2: 「ファンイン」パイプラインの構築
上記のリファクタリングの結果、パイプラインアーキテクチャは「ファンイン(Fan-in)」構造に進化します。
アプリケーションアーキテクチャ
モジュラーモノリス、あるいは分散モノリス(エピックサーガ /おとぎ話サーガ)
コードベースはモジュール化されているが、デプロイは依然として単一の成果物。(エピックサーガ期)
あるいは、
サービスは分割されたが、同期通信やDB共有により、独立してデプロイ可能ではない状態。(おとぎ話サーガ期)
CI/CDパイプラインアーキテクチャ
中央集権的なファンイン・パイプライン。
各モジュール(あるいはサービス)は 並列(ファンアウト)でCIが実行 されますが、最後の デプロイステップで集約(ファンイン) されます。
得られたメリット
・変更のリードタイム(LT)が劇的に改善
テストが並列実行されるため、フィードバックが高速化します。
・安全なリファクタリング環境
この高速なフィードバックループが 「足場」 となり、開発者は安心してアプリケーション本体のリファクタリング(モノリス → モジュラーモノリス)に着手できます。
顕在化する「痛み」(次のフェーズへのトリガー)
・デプロイの頻度(DF)が依然として低い
ファンイン構造(デプロイの集約)がボトルネックです。
Module-Orderのテストが失敗すると、全く無関係なModule-Customerのデプロイもブロックされてしまいます。
・変更障害率(CFR)が高い
全モジュールを一斉にデプロイするため、障害時の影響範囲(ブラスト半径)が依然としてシステム全体に及びます。
・課題
チームの自律性がデプロイの集約によって阻害されてしまいます。
でもこれはアーキテクチャ進化に伴い受容しないといけない、ボトルネックです。
フェーズ3:独立E2Eパイプラインへの進化(ストラングラー・パターン)
このフェーズの目的は、
「ファンインという中央集権的なボトルネックを、サービスごとに段階的に解体し、真の独立デプロイ(E2Eパイプライン)を実現すること」
です。
これには、アプリケーション側がインフラ層まで含めて非同期化・分離される(パラレルサーガ/アンソロジーサーガ等)ことが前提となります。
ステップ3.1: 移行対象の選定と「新しいつる」の構築
まず、最も独立性が高い(あるいは、独立させたい)サービスを1つ選定します
(例: Order-Service)。
次に、既存のファンイン・パイプラインとは完全に別に、Order-Service専用の
新しい「独立E2Eパイプライン」 を構築します。(ストラングラー用のパイプ)
New Pipeline (Order-Service)
Build → Test → Scan → Deploy to Staging (Order) → Deploy to Prod (Order)
このパイプラインは、他のどのパイプラインも待ちません。
ステップ3.2: 既存パイプラインの「絞め殺し」(ECRS: 排除)
次に、既存の「ファンイン・パイプライン」に戻り、
Order-Serviceに関する責務を「排除(Eliminate)」します。
Old Pipeline (Fan-in) の修正
・Unit Test (Order)のステップを削除します。
・Deploy to Production(ファンイン)ステップの依存関係(needs)から、
Unit Test (Order)を削除します。
ステップ3.3: ハイブリッド状態での運用と観測
この時点で、パイプラインアーキテクチャは以下のハイブリッド(移行期)状態になります。
・Order-Serviceは、新しいE2Eパイプラインによって高頻度かつ独立デプロイされます。
・Customer-ServiceとPayment-Serviceは、依然として古いファンイン・パイプラインによって低頻度かつ一括でデプロイされます。
この状態でシステムを運用し、Order-Serviceの独立デプロイが、他のサービスに悪影響を与えないこと(=アーキテクチャが本当に分離されているか?)を実証します。
もしもここで、悪影響を与えてしまうことが、事実データとして取れたら、それはアーキテクチャが分離できないことを意味します。
ステップ3.4: 繰り返しと古いパイプラインの解体
上記のステップ3.1〜3.3を、残りのサービス(Customer-Service, Payment-Service...)に対しても繰り返します。
①. Customer-Service用の新しいE2Eパイプラインを構築します。
②. 古いファンイン・パイプラインからUnit Test (Customer)を排除します。
...
すべてのサービスが独立E2Eパイプラインに移行し、古いファンイン・パイプラインの責務がゼロになったら、その古いパイプラインを完全に削除します。
最終的なパイプラインアーキテクチャ
・独立したE2Eパイプラインの集合体。
・各チームが、自身のサービスのFour Keysに全責任を持つ、自律的な状態が完成します。
