前置き
前回の記事の続きになります。
PoCやプロトタイピングで素早く顧客からのフィードバックを得つつ、その反復的工程の中でドメインの境界を探すことは、たしかにとても重要です。
しかし、コアドメイン、補完ドメイン、一般ドメインをMVP作成開始時に、明確にこのマトリクスのようにコンテキスト境界で分離できない場合、初期のMVP作成時には、すべての領域を同期通信で連携せざるを得ないことも多いです。
その時には、インフラ部分で集約された状態でデプロイしなくてはいけなくなります。
この時の各コアドメイン、補完ドメイン、一般ドメインのデプロイメントモデル(配置図)でのネットワークセグメントの配置状況と、CI/CDパイプラインの構造を考えてみましょう。
そして、段階的にサーバーレスアーキテクチャを取り入れていく様子を追っていきます。
デプロイメントモデル(配置図)
目的
迅速な開発とフィードバックを最優先し、厳密な分離よりもシンプルな構成を重視します。
ネットワークセグメント
Zoneベースのシンプルな分割を行います。
厳密なドメイン境界ではなく、「役割」に基づいた粗い粒度のセグメント化が現実的です。
・DMZ/Publicセグメント
UI、APIゲートウェイなど(外部公開が必要なもの)
・Appセグメント (Private)
ここが重要です。
まだコンテキスト境界が不明確なため、コアドメイン、補完ドメイン、一般ドメインの多くのコンポーネントが、この単一のAppセグメントに同居することが多いです。
この理由は下記で触れます。
もちろんこの段階で、「ここは明らかにインフラまで含めてドメインを分割してOK」と自信を持って言える部分に関してのみは、別のAppセグメントに配置してしまって大丈夫です。
・Dataセグメント (Private - Stricter)
データベース(これは通常分離されます)。
ポイント
ドメインごとの厳密な分離は行いません。
Appセグメント内は比較的自由な通信が許可されている可能性があります。
配置
・UIコンポーネント → DMZ
・ビジネスロジック (コア/支援/汎用が混在) → Appセグメント
・データベース → Dataセグメント
CI/CDパイプラインの構造
目的
すべてのコンポーネントが一貫した状態でデプロイされることを保証します。独立デプロイはできません。
構造
中央集権的なファンイン・パイプライン または 一本の線形パイプライン になります。
一本線形
最もシンプル。
1つのコミットが、全コンポーネントのビルド、テスト、デプロイを直列に実行します。
ファンイン
コードがモジュール化されていれば、各モジュールのビルドやユニットテストは、下図のように並列(ファンアウト)で実行できますが、
最終的なデプロイは、単一のステップで集約(ファンイン)
されます。
ポイント
同期通信による強い依存関係があるため、「コアだけ」「補完だけ」を個別にデプロイすることはできません。
パイプラインでは、常にシステム全体を一塊として扱います。
重要な注意点
この構成は、あくまで 初期段階(MVP) のものです。
MVPから得られるフィードバックとドメイン理解の深化に基づき、
①. 継続的にドメイン境界を明確にし、
②. 同期通信を非同期にリファクタリングし、
③. それに合わせてネットワークセグメントを細分化し、
④. 最終的にCI/CDパイプラインも独立したE2Eパイプラインへと、段階的に進化
させていく必要があります。
同一Appセグメントにする理由とトレードオフ
上記で「境界が不明確なため、コアドメイン、補完ドメイン、一般ドメインの多くのコンポーネントが、この単一のAppセグメントに同居することが多い」と書きました。
その理由や、同一のセグメントに配置することによるセキュリティ上のリスクについて触れてみましょう。
同居の理由
MVP初期では、どうしてもドメインの境界が不透明なまま事業・ソフトウェアを成長させなくてはなりません。
この段階で無理にドメインの境界を分離してしまうと、いざその境界位置が間違っていた場合に、元に戻すことが非常に困難になります。(アーキテクチャにおける可逆性の問題)
①同期通信のオーバーヘッド回避
同期通信で密結合しているコンポーネントを別々のネットワークセグメントに配置すると、以下の問題が発生します。
・レイテンシーの増加
セグメント間の通信は必ずネットワークホップとファイアウォールを経由するため、応答時間が悪化します。
・可用性の低下(結合による影響拡大)
セグメント間のファイアウォール障害や、呼び出し先セグメントの障害が、呼び出し元サービスの直接的な障害を引き起こします(爆発半径の拡大)。
・設定の複雑化
多数のファイアウォールルールを管理する必要が出てきます。
初期段階では、これらのオーバーヘッドを避けるために、物理的に近く(=同じセグメント)に配置する方が「楽」です。
②境界の不確実性
MVP初期段階では、「どこが真のコアドメインか」「どの通信を将来的に非同期にすべきか」といった境界がまだ曖昧です。
この不確実な状態で厳密なセグメント分割を行うと、後で境界が見えてきたときに大規模なネットワーク再設計が必要になるリスクがあります。
そのため、最初は
意図的に緩やかな境界(=単一のAppセグメント) にしておく
という判断がなされがちです。
セキュリティリスク
そして、この「楽さ」や「柔軟性」と引き換えに、
セキュリティレベルは最も脆弱な部分に制約されるという重大なリスクを受け入れることになります。(制約理論の考え)
もしAppセグメントに外部公開API(汎用ドメイン)と内部のコアビジネスロジック(コアドメイン)が同居していれば、そのセグメント全体のファイアウォールルールは、外部公開APIの要件(例:ポート443を開ける)に合わせる必要があります。
これにより、
本来インターネットから隔離されるべきコアドメインが、意図せず攻撃対象領域に含まれてしまうリスク
が生じます。
ここのまとめ
MVP段階で異なるドメインコンポーネントを単一セグメントに同居させるのは、
スピードと引き換えにセキュリティと将来の分離を犠牲にする
という、計算された技術的負債の選択と言えます。
時期早々なサーバーレスアーキテクチャの選定
初期段階(同期通信が多く、ドメイン境界が不明確なMVP)でサーバーレスを導入するのは時期尚早です。(これ本当によく見かけます💦)
最初は、自前のコンテナで運用しつつ、「ここは非同期にできる」かつ「ここはコアドメインではない」 と明確に判断できた部分から段階的にサーバーレスを取り入れていくのが、
アーキテクチャを健全に進化させるための理想的なアプローチです。
なぜ初期段階は「時期尚早」なのか
同期通信とのミスマッチ
サーバーレス(FaaS)はイベント駆動(非同期)に最適化されています。
同期通信が多いアーキテクチャに無理やり適用すると、コストの無駄(待機時間課金)やタイムアウトのリスクが高まります。
境界の不確実性
どこが真のコアドメインか不明確な状態で、サーバーレスの制約(ステートレス、実行時間制限)を導入すると、将来の コアドメインの成長を阻害 してしまうリスクがあります。
コンテナの必要性
この段階では、状態を持つ可能性のあるロジックや、同期通信のラッパーとして、コンテナ(あるいはVM) で運用する方がはるかに柔軟で安全です。
段階的なサーバーレス導入の理想的なプロセス
上記の状態から
「ここはインフラ層で非同期にしてもいい。しかもこの領域はコアドメインではない。」と判断できたところから段階的にサーバーレスを取り入れる
というのが、安全であり理想です。
1. 観測と学習
まずはコンテナベースでMVPを運用し、
「どこがボトルネックか」
「どの通信が本当に同期である必要があるか」
「どこが安定していて変更が少ないか(=汎用/支援ドメインの可能性)」
といった知見(事実データ)を集めます。
2. 境界の特定
DDDの原則に基づき、ドメイン境界を明確にしていきます。
3. 最初の候補の選定
以下の条件を満たす最初の候補(機能やプロセス)を特定します。
・非同期化可能:即時性が不要で、イベント駆動にリファクタリングできる。
・非コアドメイン:ロジックが比較的単純で、将来の大きな変更が見込まれない(支援/汎用サブドメイン)。
4. サーバーレスへの移行 (Strangler Fig)
①. 特定した機能を、サーバーレス(FaaS)として“横に” 構築します。
②. 既存のコンテナ(モノリス)から、その機能への呼び出しを、新しいサーバーレス関数への イベント発行(またはAPIコール) に切り替えます。
③. 最終的に、コンテナ内の古いロジックを削除します。
5. 繰り返す
このプロセスを、サーバーレスに適した他の候補に対しても繰り返していきます。
まとめ
このアプローチにより、サーバーレスのメリット(運用コスト削減、スケーラビリティ)を享受しつつ、コアドメインの成長可能性を犠牲にすることなく、アーキテクチャを安全に進化させることができます。


