はじめに~C4モデルの基本概念~
アーキテクトになりたい方、現役のアーキテクトの方々、
C4モデルというものを聞いたことはあるでしょうか?
C4モデルは、単なる作図ツールではなく、ビジネスの要求から実装の詳細までの認知負荷をコントロールするための強力な思考フレームワークです。
アーキテクチャ決定の可視化
もっともマクロなモデルから徐々にブレイクダウンしていくのですが、図の作成自体が目的ではなく、どこにトレードオフが存在し、どう決定を下したのかというADR(Architecture Decision Record)を浮き彫りにするメカニズムとして機能します。
わたしは、毎回このC4モデルを必ずと言っていいほど使っています。
なんでかっていうと、
各ステークホルダーの視点ごとの要求を抽象度ごとにプロットしやすいんです。
要求がアーキテクチャを決定づけます。
ゆえに、アーキテクチャを決定する際に、余計な手戻りを最小限にしやすいです。
C4モデルにおける階層間のズームイン・ズームアウトと整合性維持のメカニズム
C4モデル全体を貫く根本的なメカニズムは、階層を切り替えることで議論の対象とオーディエンス(誰と何を話すか)を強制的に分離する「ズームイン・ズームアウトの原則」です。
ズームイン・ズームアウトてのは、具体と抽象のこと。
各階層はこの原則に基づいて連動し、上位層の境界を維持したまま内部構造を詳細化することでシステム全体のダイナミズムと整合性を担保する。
システムコンテキスト層からコンテナ層へのトランジション
システムコンテキスト図で定義したアクターと外部システムを、コンテナ図の周囲に全く同じ名前・同じ関係性で配置し、システムの箱を開けて内部コンテナとの結びつきを描く。
コンテナ層からコンポーネント層へのトランジション
コンテナ図で定義した外部依存関係は、コンポーネント図内の特定のモジュール(例: Repository層)から伸びる矢印として出自を明確にする。
このコンポーネントレベルまで具体化されると、この視点のものには、Biz側は関心を持ちにくいほど詳細です。
1. システムコンテキスト図(ビジネス境界の定義)
では、まずはもっともマクロな抽象度のモデルから行きましょう。
すべての抽象度で、ドメイン駆動の考え方が活きてきます。
このシステムコンテキストは、C4の中で最もマクロな視点であり、
「誰が(アクター)、どのシステムを使って価値を得るのか」
を定義するレベル1のビューである。
対象読者
ビジネススポンサー、プロダクトマネージャー、非エンジニア。
決定するアーキテクチャ要素
システムの境界、関与するアクター、外部システムとの依存関係。
下図のようなシステム境界やアクターの関係性を描きます。
この図は、あくまでも様々なシステムの関係の構造スナップショット。
これだけでなく、動的なプロセスのモデルもあります。(それは後述)
関連プラクティスとの統合
BPR・DDDとの連携
「WhyとWho」を決定し、ビジネスのボトルネックを解消するコアドメインを特定する。
実務上、この図の「システム」はDDDの境界づけられたコンテキスト(単一または複数)とマッピングされる。
イベントストーミングとの連携
Big Pictureレベルのイベントストーミングが強力なインプットとなる。
ここのイベントストーミングは、次のコンテナレベルのイベントストーミングよりもマクロなものです。
マクロなイベント連鎖からシステムの境界を切り出すため、ここでの結果整合性は数秒〜数日単位の「弱い整合性」となる。
RDRAのシステムコンテキストとの関係
RDRAでも、この外部システムと「ビジネスイベント」を介して連携するというモデルを描くので、それのことだと思ってほしい。
なぜなら、RDRAで描くのは、このレベル1の抽象度のモデルを通して、BizとDevの共通理解を深めることなんだから。
モデリングの制約(KISS原則)
ユースケース記述ではない
対象システムは「ブラックボックス」として描き、内部の細かいユースケースは記述しない(動的なストーリーはアクティビティ図等を併用する)。
インフラ技術に依存させない
クラウドプロバイダ(AWS等)などのインフラ依存関係を描くことは「階層の混同」であり、デプロイメント図で行うべきである。
関心の分離および、抽象に依存させよという設計思想
2. コンテナ図(デプロイ単位と組織境界の定義)
ソフトウェアアーキテクトやSREにとって最も重要な意思決定が行われるレベル2の主戦場。
先ほどの、システム境界で囲まれた部分を、一段階ズームインします。
ここで気を付けたいのが、
Dockerコンテナとかの、コンテナのことではない
ということ。
対象読者
ソフトウェアアーキテクト、SRE、セキュリティアーキテクト、インフラエンジニア。
決定するアーキテクチャ要素
独立して実行・デプロイ可能な単位(マイクロサービス、DB、Webアプリ等)と通信プロトコル。
図のように、対象システムを1段階ブレイクダウンして、中身がどんなサービス群によって成立しているか?を明らかにします。
UAFというフレームワークでいうところの、Servicesビューのことを指します。
関連プラクティスとの統合
イベントストーミングとの連携
ここのレベルのイベントストーミングが、最も巷でよく行われている部分です。
サービス同士の連携をビジネスプロセスモデリングします。
チームトポロジーとの連携
コンウェイの法則に基づき、コンテナの境界がストリームアラインドチームの認知負荷や責任範囲と一致しているかを検証する。
アーキテクチャ量子との連携
高凝集かつ独立デプロイ可能な「アーキテクチャ量子」同士の関係性を可視化するビューとなる。
分散トランザクション(Saga)との連携
同期通信と非同期通信のトレードオフを評価し、Sagaパターンの適用範囲(結果整合性の範囲)と可用性のフォールバックを決定する。
セキュリティモデリングとの連携
脅威モデリングにおけるトラストバウンダリ(信頼境界)は、主にこのコンテナ間通信に定義される。
3. コンポーネント図(内部構造と関心の分離)
1つのコンテナ(マイクロサービス量子等)の内部にズームインし、内部構造を定義するレベル3のビューである。
ようは、1つのクリーンアーキテクチャ同心円内をどう関心分けるか?を考える。
対象読者
開発チーム、テックリード、QA、セキュリティエンジニア。
決定するアーキテクチャ要素
コンテナ内部の主要モジュール(コントローラー、ユースケース、リポジトリ等)とインターフェース。
関連プラクティスとの統合
クリーンアーキテクチャとの連携
ここで、クリーンアーキテクチャやヘキサゴナルアーキテクチャの概念が登場します。
コントローラー(Web層)、ユースケース(アプリケーション層)、ドメインサービス、リポジトリ(インフラ層)などの主要なモジュールを「コンポーネント」として描き、それらの依存の方向(依存関係逆転の原則が守られているか等)を可視化します。
DDDの「集約」との境界線
コンポーネント図は「アーキテクチャ上のモジュール」を描く。
データ一貫性の境界である「集約」はさらに内部の概念であるため、ドメインモデル全体を1つのコンポーネントとし、詳細は下位層へ委譲する。
上位図との整合性の保ち方
1つ上のコンテナ図で定義した、そのマイクロサービスの「外部依存(例:DBへの接続、他のAPIへの呼び出し)」は、コンポーネント図内の特定のコンポーネント(例:XxxRepositoryやXxxApiClient)から伸びる矢印として表現されなければなりません。
これにより、「どの内部モジュールが、どの外部コンテナと通信しているのか」という整合性が担保されます。
4. コード図(実装の詳細)
クラス図やER図などを扱う、最もミクロなレベル4のビューである。
対象読者
プログラマーやテスター。
運用の原則
メンテナンスコストが高騰するため、このレベル4の明示的なドキュメント化はスキップし、IDE等の自動生成ツールに任せることが推奨されます。
アーキテクチャ評価におけるアンチパターン
C4モデルを用いたレビューにおいて、排除すべき代表的なアンチパターンは以下の通りである。
階層の混同
システムコンテキスト図にインフラ技術(DBやメッセージキュー等)を混入させ、ビジネス要件を不明瞭にすること。
これは、モデル上で関心の分離ができていないってこと。
起こる問題①
まず、レベル1でのみ議論したいのに、余計な枝葉が大量に出ているので、利害関係者との認識合わせに時間がかかります。
起こる問題②
モデルの保守運用が行いにくくなります。
レベル3以降のみ変えればよく、レベル2よりマクロな部分は再利用できるって時とかでも、混同されていると、その切り分けが行いにくくなります。
仮に全部のレベルでモデルを修正が必要となっても、レベルごとに関心が分けられている方が、どこを修正したらいいかっていうのがすぐにわかるので便利です。
起こる問題③
セキュリティ脅威分析が行いにくいです。
脅威モデリングを実際にやってみて感じましたが、このレベルごとのDFDを描くか描かないかで、脅威モデリングの行いやすさは劇的に変わります。
コンテナ粒度の不整合
独立デプロイの必要性がないにも関わらず細分化し、「分散モノリス化」によるSREの運用コスト増大を招くこと。
独立デプロイ可能ってことは、CI/CDパイプラインもサービスごとに一本一本独立したE2E構造ってことです。
データ所有権の喪失
複数のコンテナが同一のデータベースを直接読み書きし、データのライフサイクル責任が曖昧になること(データベースインテグレーション)。
これよくあるあるだと思います。
基本的には、DBの所有権は、単独所有です。
詳しい話は、以下の本がすごく参考になります。
どのように、サービスロジックに業務DBの所有権を割りあてるか?の設計パターンが載っています。




