C4 Model — это способ визуально описывать архитектуру программной системы через последовательное приближение, от общей картины до внутреннего устройства конкретного приложения.
Название C4 происходит от четырёх уровней:
- System Context
- Container
- Component
- Code
Логика похожа на карту:
- сначала показываем страну;
- затем город;
- затем конкретное здание;
- затем комнаты внутри здания.
Главная идея C4: не пытаться изобразить всю архитектуру на одной гигантской диаграмме.
1. System Context Diagram
Что показывает
Контекстная диаграмма отвечает на вопрос:
Что это за система, кто ею пользуется и с какими внешними системами она взаимодействует?
На ней обычно присутствуют:
- проектируемая система;
- пользователи или роли пользователей;
- внешние системы;
- основные связи между ними.
Например, для системы бронирования отелей:
[Пользователь]
|
v
[Система бронирования отелей]
|
+----> [Платёжный провайдер]
|
+----> [Система отеля]
|
+----> [Email/SMS-провайдер]
Здесь не показываются:
- микросервисы;
- базы данных;
- Kafka;
- Redis;
- внутренние API;
- классы;
- конкретные технологии.
Для кого предназначена
Контекстная диаграмма понятна практически всем:
- бизнесу;
- менеджерам;
- аналитикам;
- разработчикам;
- архитекторам;
- новым участникам проекта.
Главный вопрос уровня
Где проходит граница нашей системы?
Это важнейший вопрос. Пока граница системы не определена, обсуждать микросервисы рано.
2. Container Diagram
Что такое container в C4
В C4 слово container не означает исключительно Docker-контейнер.
Container здесь — это отдельно запускаемая или развёртываемая часть системы.
Контейнером может быть:
- backend-приложение;
- frontend-приложение;
- мобильное приложение;
- микросервис;
- база данных;
- message broker;
- отдельный batch-процесс;
- сервер авторизации.
Например:
[Пользователь]
|
v
[Web Application]
React / TypeScript
|
v
[Backend API]
Java / Spring Boot
/ | \
v v v
[PostgreSQL] [Redis] [Kafka]
На этом уровне уже можно показывать технологии:
- Java;
- Spring Boot;
- PostgreSQL;
- Redis;
- Kafka;
- React;
- Android;
- Kubernetes.
Что показывает Container Diagram
Она отвечает на вопросы:
- из каких крупных исполняемых частей состоит система;
- где хранится информация;
- какие приложения вызывают друг друга;
- какие технологии используются;
- какие обязанности принадлежат каждому контейнеру.
Например:
[Web Application]
Позволяет пользователю искать отели и создавать бронирования.
[Booking API]
Обрабатывает поиск, бронирование и отмену.
[PostgreSQL]
Хранит пользователей, бронирования и инвентарь номеров.
[Redis]
Хранит кэш результатов поиска и временные блокировки.
[Kafka]
Передаёт события BookingCreated, BookingCancelled.
Главный вопрос уровня
Из каких отдельно работающих частей состоит система?
Именно Container Diagram обычно является основной диаграммой на system design interview.
На собеседовании, когда ты рисуешь:
- API Gateway;
- Booking Service;
- Payment Service;
- PostgreSQL;
- Redis;
- Kafka;
ты фактически создаёшь C4 Container Diagram, даже если не называешь её этим термином.
3. Component Diagram
Что такое компонент
Component в C4 — это логически выделенная часть внутри контейнера.
Например, внутри Booking Service могут быть:
[Booking Controller]
|
v
[Booking Application Service]
|
+----> [Availability Component]
|
+----> [Pricing Component]
|
+----> [Booking Repository]
|
+----> [Event Publisher]
Component Diagram отвечает на вопрос:
Как устроен конкретный контейнер изнутри?
Например, контейнер:
Booking Service
может состоять из компонентов:
- Booking API;
- Booking Application Service;
- Availability Checker;
- Pricing Engine;
- Booking Repository;
- Payment Client;
- Event Publisher;
- Idempotency Handler.
Важное различие
Компонент — это не обязательно:
- отдельный процесс;
- отдельный микросервис;
- отдельный deployment;
- отдельный Docker-контейнер.
Компоненты обычно работают внутри одного приложения и одного процесса.
Например:
Booking Service
└── BookingController
└── BookingService
└── AvailabilityService
└── BookingRepository
└── OutboxPublisher
Все эти компоненты могут находиться внутри одного Spring Boot-приложения.
Главный вопрос уровня
Какие внутренние архитектурные части реализуют ответственность контейнера?
4. Code Diagram
Code Diagram показывает реализацию отдельного компонента на уровне кода.
Это могут быть:
- классы;
- интерфейсы;
- структуры;
- модули;
- функции;
- отношения наследования;
- зависимости между классами.
Например:
BookingController
|
v
BookingService
|
+----> AvailabilityService
|
+----> BookingRepository
|
+----> PaymentGateway
Или подробнее:
interface BookingRepository {
Booking save(Booking booking);
Optional<Booking> findById(BookingId id);
}
class BookingService {
private final BookingRepository repository;
private final AvailabilityService availabilityService;
}
На этом уровне C4 часто пересекается с UML:
- class diagram;
- package diagram;
- dependency diagram.
Главный вопрос уровня
Какими программными конструкциями реализован компонент?
Но этот уровень используется значительно реже остальных.
Причина проста: код меняется быстро, и подробные диаграммы классов быстро превращаются в архитектурные окаменелости.
Полная иерархия
Software System
|
+-- Container
|
+-- Component
|
+-- Code
Например:
Hotel Booking Platform System
|
+-- Booking Service Container
|
+-- Availability Component Component
|
+-- AvailabilityService Code
+-- InventoryRepository Code
+-- DateRange Code
Каждый следующий уровень увеличивает детализацию, но уменьшает область изображения.
Пример C4 для системы бронирования отелей
Level 1: Context
[Клиент]
|
v
[Hotel Booking System]
|
+----> [Payment Provider]
+----> [Hotel Management System]
+----> [Notification Provider]
На этом уровне система бронирования является одним прямоугольником.
Level 2: Containers
[Web Application]
|
v
[API Gateway]
|
+----> [Search Service] ------> [OpenSearch]
|
+----> [Booking Service] -----> [Booking PostgreSQL]
| |
| +--------------> [Redis]
| |
| +--------------> [Kafka]
|
+----> [Payment Service] -----> [Payment Provider]
|
+----> [Notification Service] -> [Email/SMS Provider]
Здесь уже видна техническая архитектура.
Level 3: Components внутри Booking Service
[Booking REST Controller]
|
v
[Booking Application Service]
|
+----> [Availability Checker]
|
+----> [Booking Domain Model]
|
+----> [Booking Repository]
|
+----> [Inventory Lock Manager]
|
+----> [Outbox Event Publisher]
Здесь мы раскрываем только один контейнер, Booking Service.
Не нужно одновременно раскрывать внутренности всех микросервисов. Иначе диаграмма снова превращается в архитектурные макароны.
Level 4: Code внутри Availability Checker
AvailabilityService
|
+-- AvailabilityRepository
|
+-- ReservationPolicy
|
+-- DateRange
|
+-- RoomTypeId
|
+-- AvailabilityResult
C4 не определяет архитектуру
Это принципиальное различие.
C4 не говорит, что нужно использовать:
- микросервисы;
- Kafka;
- Kubernetes;
- Clean Architecture;
- DDD;
- REST;
- PostgreSQL.
C4 только задаёт способ показывать уже выбранную архитектуру.
То есть:
Архитектурное решение:
использовать Booking Service и PostgreSQL.
C4:
способ отобразить Booking Service и PostgreSQL на диаграмме.
Нельзя сказать:
Мы построили систему по архитектуре C4.
Точнее будет:
Мы описали архитектуру системы с помощью модели C4.
C4 и UML
C4 не является прямой заменой UML.
UML
UML содержит большое количество типов диаграмм:
- class diagram;
- sequence diagram;
- component diagram;
- deployment diagram;
- activity diagram;
- state machine diagram;
- use case diagram.
UML формальнее и детальнее.
C4
C4 даёт простую иерархию масштабов:
Context → Container → Component → Code
Его преимущество в том, что человек сразу понимает:
- какой уровень он сейчас видит;
- что находится внутри рассматриваемого объекта;
- какая детализация намеренно скрыта.
C4 можно считать способом организации архитектурных представлений, а UML можно использовать внутри отдельных уровней C4.
Например:
- C4 Context Diagram для общей картины;
- C4 Container Diagram для сервисов;
- sequence diagram для сценария бронирования;
- state machine diagram для жизненного цикла бронирования;
- deployment diagram для Kubernetes-инфраструктуры.
Статическая и динамическая архитектура
Основные четыре уровня C4 показывают преимущественно статическую структуру:
- какие элементы существуют;
- как они связаны;
- кто от кого зависит.
Но они не всегда хорошо показывают последовательность выполнения операции.
Например, Container Diagram может показать:
Booking Service → Payment Service
Однако она не объясняет:
- когда вызывается Payment Service;
- сначала блокируется номер или списываются деньги;
- что происходит при ошибке;
- как выполняется компенсация;
- где используется идемпотентность.
Для этого нужна динамическая диаграмма:
User
|
v
Booking API
|
v
Inventory Service: hold room
|
v
Payment Service: authorize payment
|
v
Booking Service: confirm booking
|
v
Kafka: BookingConfirmed
Поэтому C4 обычно дополняют:
- sequence diagrams;
- dynamic diagrams;
- deployment diagrams;
- state diagrams;
- data models.
Какие элементы должны быть подписаны
Хороший элемент C4 содержит три вещи:
[Название]
[Тип или технология]
[Ответственность]
Например:
Booking Service
[Java / Spring Boot]
Создаёт, подтверждает и отменяет бронирования.
Управляет жизненным циклом бронирования.
Плохой вариант:
Service 1
Service 2
Database
Queue
Такие названия показывают геометрию системы, но не её смысл.
Связи тоже желательно подписывать:
Booking Service
|
| Creates payment authorization
v
Payment Service
А не просто рисовать стрелку без объяснения.
Что считается ошибкой в C4
1. Смешивание уровней
Например, на одной диаграмме одновременно показаны:
User
Booking Platform
Booking Service
BookingController
BookingRepository
PostgreSQL table bookings
Kubernetes Pod
Здесь смешаны:
- context;
- container;
- component;
- code;
- deployment;
- data model.
Получается не C4, а архитектурный винегрет.
2. Изображение технологий вместо ответственности
Например:
Java Service
Redis
Kafka
PostgreSQL
Но непонятно:
- что делает Java Service;
- зачем используется Redis;
- какие события передаются через Kafka;
- какие данные лежат в PostgreSQL.
Технология не заменяет назначение.
Лучше:
Booking Service
Создаёт и отменяет бронирования.
Redis
Хранит кратковременные блокировки доступности.
Kafka
Передаёт события изменения состояния бронирования.
3. Попытка показать всё
C4 не требует одной полной энциклопедической диаграммы.
Можно иметь:
1 Context Diagram
1 общую Container Diagram
3 Component Diagram:
- Booking Service
- Payment Service
- Search Service
Необязательно рисовать Component Diagram для каждого сервиса.
4. Представление базы данных как нейтральной общей коробки
Если несколько сервисов используют одну базу, это должно быть видно.
Например:
Booking Service ----\
> Shared Database
Payment Service ----/
Такая схема означает архитектурную связанность. Общая база превращается в скрытую точку интеграции.
C4 не запрещает это, но делает зависимость видимой.
C4 на System Design Interview
На собеседовании обычно достаточно двух уровней.
Сначала Context
Очень кратко:
Пользователь → Система бронирования → Отели / Платежи / Уведомления
Это фиксирует границы задачи.
Затем Containers
Основная рабочая диаграмма:
Client
|
Load Balancer / API Gateway
|
+-- Search Service
+-- Booking Service
+-- Payment Service
+-- Notification Service
|
PostgreSQL / Redis / Kafka / OpenSearch
Затем точечное приближение
Когда интервьюер спрашивает:
Как избежать двойного бронирования?
Ты приближаешь только соответствующую часть:
Booking Service
|
+-- Availability Checker
+-- Inventory Lock Manager
+-- Booking Repository
+-- Idempotency Handler
После этого можно показать последовательность:
Check availability
→ acquire hold
→ create pending booking
→ authorize payment
→ confirm booking
→ publish event
Это и есть практическая сила C4: архитектура раскрывается по запросу, а не вываливается на стол целиком.
Как понимать C4 одной формулой
Context:
кто взаимодействует с системой.
Container:
из каких запускаемых частей состоит система.
Component:
из каких логических частей состоит отдельное приложение.
Code:
какими конструкциями реализована отдельная логическая часть.
Самая полезная мысль:
C4 управляет не самой архитектурой, а масштабом разговора об архитектуре.
Она не даёт смешивать пользователя, микросервис, Java-класс и таблицу PostgreSQL в одном визуальном котле. Каждый уровень отвечает на свой вопрос и скрывает детали, которые в данный момент не нужны.