C4モデルの詳細解説:レベル1からレベル4まで

ソフトウェアアーキテクチャは、しばしばホワイトボードにボックスを描くことだけだと誤解されている。実際には、技術的実装とビジネス理解の間のギャップを埋めるコミュニケーションの分野である。C4モデルは、抽象度の異なるレベルでソフトウェアアーキテクチャを可視化する構造的なアプローチを提供する。このガイドでは、各レイヤーを検討し、いつそれらを適用すべきか、誰がそれらを閲覧すべきか、そしてそれらがどのように統合されてシステムの整合性のある画像を構成するかを詳しく説明する。

🌍 アーキテクチャ図の標準化の理由は何か?

標準がないと、チームは有用でないほど曖昧な図、または維持できないほど詳細な図を作成しがちである。一部のチームは、ビジネス関係者がプロセスの概要を必要としているときにネットワーク図を描く。他のチームは、開発者がデータフローを理解するだけでよいときにクラス図を作成する。C4モデルは、それぞれが明確な目的と対象を持つ4つの特定のレベルを定義することで、この問題を解決する。

核となる哲学は単純だ:1枚の図ではすべてを示すことはできない。代わりに、地図のようにズームイン・ズームアウトできる図のセットを作成する。世界地図は国を示し、都市地図は通りを示し、通り地図は個々の建物を示す。C4モデルは、ソフトウェアにも同じ論理を適用する。

📍 レベル1:システムコンテキスト

システムコンテキスト図は、高レベルの視点である。この図は、「このシステムはどのような機能を果たし、誰がそれを使用するのか?」という問いに答える。これは、新しいプロジェクトを開始するときや、既存のシステムを文書化する際に、しばしば最初に作成される図である。

🎯 主な対象者

  • ビジネス関係者:技術用語を使わずに範囲を理解したいプロダクトマネージャー、経営陣、クライアント。
  • 新規チームメンバー:プロジェクトに参加する開発者で、エコシステムの概要を素早く理解したい人。
  • 外部パートナー:自社のシステムとどのように連携するかを把握したい、第三者のベンダー。

📦 図の中には何が入るか?

システムコンテキスト図は、正確に3つの要素から構成される:

  • 1つのソフトウェアシステム:これは説明対象のシステムである。図の中心に配置される。
  • 人:システムとやり取りするユーザー。エンドユーザー、管理者、サポートスタッフなどが含まれる。
  • 他のシステム:自社のシステムとやり取りする外部のソフトウェアシステム。API、データベース、レガシープラットフォームなどを含む。

🔗 関係性と信頼

線は中心のシステムと人々、他のシステムを結ぶ。これらの線は関係性とデータフローを表す。やり取りの方向を明確にすることが重要である。たとえば、システムが外部システムにデータをプッシュするのか、それともデータをプルするのか。

信頼境界もここに視覚化されることが多い。点線が自社のシステムと外部パートナーを分けることで、信頼度が低い、または異なるセキュリティドメインであることを示す。これにより、セキュリティチームが境界がどこにあるかを理解しやすくなる。

🏭 レベル2:コンテナ

コンテキストが理解されたら、次にズームインする。コンテナレベルは、「このシステムの主要な構成要素は何ですか?」という問いに答える。コンテナとは、明確に区別された実行環境である。マイクロサービスではないが、マイクロサービスはコンテナである。データベースではないが、データベースもコンテナである。これは、自己完結したデプロイメント単位である。

🎯 主な対象者

  • 開発者:技術スタックと境界を理解したいエンジニア。
  • DevOpsエンジニア:デプロイ、スケーリング、モニタリングを担当するチーム。
  • アーキテクト:システムの異なる部分間の統合パターンを設計する者たち。

📦 中身は何か?

コンテナ図は、レベル1の単一の「ソフトウェアシステム」をその構成要素に分解する。一般的なコンテナには以下が含まれる:

  • Webアプリケーション:ブラウザベースのフロントエンド(例:React、Angularアプリ)。
  • モバイルアプリケーション:iOSまたはAndroidネイティブアプリ。
  • API:REST、GraphQL、またはgRPCエンドポイント。
  • データベースシステム:SQLまたはNoSQLストア。
  • コマンドラインツール:メンテナンスに使用されるスクリプトまたはユーティリティ。

🔗 準備

コンテナ間の接続は、それらがどのように通信するかを示す。使用されるプロトコルを明確にすることが重要である。HTTPか?RabbitMQのようなメッセージキューか?直接のTCP接続か?

レベル1とは異なり、レベル2の図ではコンテナ間の信頼境界を含むことが多い。例えば、WebアプリケーションはDMZ(非軍事区域)に配置される一方、データベースはセキュアな内部ネットワーク内に配置される。この分離を可視化することで、設計段階の初期にセキュリティリスクを特定できる。

🧩 レベル3:コンポーネント

さらにズームインすると、コンポーネントレベルは「コンテナの中身は何か?」という問いに答える。ここにシステムのロジックが存在する。コンテナをより小さな、一貫性のある部分に分解する。コンテナには多くのコンポーネントが含まれるが、コンポーネントは一つのコンテナにのみ属する。

🎯 主な対象者

  • ソフトウェアエンジニア:実際のコードを書く開発者。
  • システムデザイナー:アプリケーションの内部構造を定義する者たち。
  • QAエンジニア:特定のロジックフローに基づいてテストケースを計画するチーム。

📦 中身は何か?

コンポーネントは機能の論理的なグループを表す。物理的なファイルではなく、概念的なモジュールである。例には以下が含まれる:

  • 認証サービス:ログインおよびセッション管理を担当します。
  • 決済プロセッサ:銀行APIと連携します。
  • レポートエンジン:PDFやデータ可視化を生成します。
  • キャッシュマネージャ:メモリ内データストレージを管理します。

🔗 内部ロジック

このレベルでは、デプロイからロジックへ焦点が移ります。コンポーネント間の接続は、データがアプリケーション内でどのように流れているかを示します。たとえば、「ユーザーインターフェース」コンポーネントから「ビジネスロジック」コンポーネント、そして「データアクセス」コンポーネントへと線を引くことができます。

このレベルは結合度を理解する上で非常に重要です。2つのコンポーネント間に多くの依存関係がある場合、リファクタリングが必要になるかもしれません。一方、依存関係のないコンポーネントは、独立したユーティリティであり、別のコンテナに移動できる可能性があります。

💻 レベル4:コード

最終的なレベルはコードレベルです。このレベルは「このコンポーネントはどのように実装されていますか?」という問いに答えるものです。この図はクラス、インターフェース、メソッドを示します。最も詳細な視点であり、高レベルなアーキテクチャではほとんど使用されません。

🎯 主な対象者

  • ジュニア開発者:コードベースの構造を学んでいる人。
  • コードレビュアー:特定のロジックパスを分析している人。

📦 中身には何が入る?

コード図はクラス図に似ています。以下を示します:

  • クラス名。
  • 属性(変数)。
  • メソッド(関数)。
  • 関係性(継承、組成、関連)。

🔗 使用するタイミング

レベル4の図は非常に複雑になり、維持が難しくなることがあります。コードは頻繁に変更されます。図がコードと同期していない場合、無駄な情報(ノイズ)になります。したがって、このレベルはできるだけ控えめに使用すべきです。

複雑なアルゴリズムや、クラス間の相互作用を理解する必要がある特定のデザインパターンにおいて、最も有用です。ほとんどのアーキテクチャ討論では、レベル3で十分です。すべての意思決定でレベル4が必要だと感じている場合、議論の対象としてアーキテクチャがしすぎている可能性があります。

📊 C4レベルの比較

違いを明確にするために、以下の表は各レベルの範囲、対象者、メンテナンス頻度を要約しています。

レベル 焦点 主な対象者 粒度 保守作業の負荷
レベル1 システムの文脈 関係者、新入社員 高い(1つのシステム) 低い(ほとんど変化しない)
レベル2 コンテナ 開発者、DevOps担当者 中程度(5〜15コンテナ) 中程度(デプロイ時に変更)
レベル3 コンポーネント エンジニア、デザイナー 低い(コンテナごとに複数) 高い(機能の変更に伴って変化)
レベル4 コード ジュニア開発者、レビュアー 非常に低い(クラス/メソッド) 非常に高い(コミットに伴って変化)

🛠️ ドキュメント作成のベストプラクティス

図を描くのは簡単ですが、有用な状態を保つのは難しいです。アーキテクチャドキュメントが長期間にわたり価値を持続するようにするための戦略を以下に示します。

📝 最新の状態を保つ

古くなった図は、図がないよりも悪いです。誤った安心感を生み出します。システムに変更が生じた場合は、図を更新してください。可能であれば、図の更新をデプロイパイプラインに統合するか、プルリクエストの必須条件としましょう。

🎨 一貫した記法を使用する

すべての図が同じ視覚ルールに従うようにしてください。ある図でデータベースが円筒であるなら、すべての図で同じようにしてください。ユーザーが棒人間であるなら、それを維持してください。一貫性があることで、読者の認知負荷が軽減されます。

🚫 過剰な詳細化を避ける

レベル2の図では、すべてのAPIエンドポイントを描画しないでください。主要な境界に注目してください。すべてのエンドポイントを表示する必要がある場合は、別途API仕様書を作成してください。図は地図を示すものであり、すべての住所を示すものではありません。

🔍 「なぜ」に注目する

存在するものだけを示すのではなく、その理由を説明してください。設計意思決定を説明する注釈を図に追加してください。特定のデータベースが選ばれた理由は何か?この2つのコンテナの間にメッセージキューがある理由は何か?これらのメモは、図だけでは伝えきれない文脈を提供します。

⚠️ 一般的な落とし穴

経験豊富なアーキテクトですら、図を作成する際に罠にはまることもあります。これらの一般的なミスに気づいておくことで、明確さを保つことができます。

❌ 「データフロー」の罠

多くのチームが、アーキテクチャとデータフローを混同しています。図は静的構造を示すべきです。何が存在し、どのように接続されているかを示すものです。イベントの順序(例:「ユーザーがボタンをクリック → APIがDBを呼び出し → 応答が返る」)を示してはいけません。これはシーケンス図であり、C4図ではありません。C4図は静的であることを保つことで、混乱を避けることができます。

❌ 信頼境界を無視する

セキュリティはしばしば後回しにされます。複数のコンテナがある場合は、信頼境界を明確に定義してください。Webアプリがデータベースを直接信頼するのか?それとも中間のAPIレイヤーがあるのか?セキュリティ境界を誤って表現すると、本番環境での脆弱性につながる可能性があります。

❌ 適切でないレベルを使用する

レベル3の詳細をプロダクトマネージャーに見せると圧倒されてしまいます。開発者にレベル1の詳細を見せても不十分です。図のレベルを読んでいる人の属性に合わせて調整してください。不安な場合は、概要ビュー(レベル2)を提供し、詳細ビュー(レベル3)へのリンクを張ってください。

❌ 一つの図ですべてを支配する

システム全体を1枚の画像に収めようとすると、ごちゃごちゃになります。階層構造を受け入れましょう。『システムコンテキスト』ページ、『コンテナ』ページ、『コンポーネント』ページを作成してください。それらをリンクして、ユーザーが必要に応じて詳細に掘り下げられるようにしてください。

🔄 メンテナンスと進化

ソフトウェアは静的ではありません。要件は変化し、技術は進化し、レガシーコードは廃止されます。C4モデルは、全体のアーキテクチャを再描画せずに特定のレベルを更新できるため、この進化をサポートします。

📅 図のバージョン管理

コードと同様に、図にもバージョン管理が必要です。大きなアーキテクチャ変更が発生した場合は、図の新しいバージョンを作成してください。これにより、システムがどのように進化してきたかを過去にさかのぼって確認できます。チームにとって貴重な歴史的記録になります。

🤝 チーム協働

アーキテクチャは単独作業ではありません。チームが図に貢献するよう促してください。開発者がコードを更新する際、彼らがコンポーネント図を更新する最適な人材です。これにより、ドキュメントがコードベースの現実を反映していることを保証できます。

🏁 これから先へ

C4モデルを採用するには、マインドセットの変化が必要です。『美しい図を描く』という焦点から『有用なコミュニケーションツールを作成する』という焦点へと移行します。各レベルの明確な目的を理解することで、ソフトウェアの複雑さに応じて拡張可能なドキュメント戦略をチームは構築できます。

まずレベル1から始め、すべての人が範囲に合意できるようにします。レベル2で技術的境界を定義します。レベル3で開発をガイドします。特定の論理を深く説明する必要がある場合にのみレベル4を使用します。これらの原則に従うことで、アーキテクチャドキュメントが忘れ去られたアーティファクトではなく、常に活きている資産のまま保たれます。

目的は明確さです。新しいメンバーがチームに加わったとき、あなたの図を見れば数分でシステムを理解できるべきです。ステークホルダーが変更の影響について尋ねたとき、コンテナやコンポーネントを通じてその経路を追跡できるべきです。これがC4モデルの真の価値です。