C4 Model простыми словами: как описывать архитектуру системы
Когда система становится сложнее одного приложения и одной базы данных, обычного списка технологий быстро перестаёт хватать.
Например, можно написать:
React
Django
PostgreSQL
Redis
RabbitMQ
Celery
MinIO
Keycloak
Но такой список почти ничего не говорит об архитектуре.
Непонятно:
- какие пользователи работают с системой;
- где проходит её граница;
- какие внешние системы существуют;
- за что отвечает Django;
- зачем нужен Redis;
- кто публикует сообщения в RabbitMQ;
- какие процессы выполняет Celery;
- где используется MinIO;
- является ли Keycloak частью системы или внешней зависимостью;
- как всё это взаимодействует между собой.
Для описания таких систем используется C4 Model.
Главная идея C4 очень проста:
Архитектуру нужно показывать на нескольких уровнях детализации, как карту с разным масштабом.
Сначала мы смотрим на систему издалека.
Потом приближаемся и видим приложения и хранилища.
Потом открываем конкретное приложение и смотрим, из каких крупных компонентов оно состоит.
Упрощённо:
System Context -> кто использует систему и с чем она взаимодействует
Container -> из каких приложений и хранилищ состоит система
Component -> из каких крупных компонентов состоит отдельное приложение
Code -> как устроена реализация компонента на уровне кода
Дополнительно C4 предлагает использовать Dynamic и Deployment Diagram для описания сценариев взаимодействия и физического развёртывания.
Что такое C4 Model
C4 Model - способ визуального описания архитектуры программных систем.
Название C4 происходит от четырёх уровней:
Context
Container
Component
Code
Идея заключается не в том, чтобы нарисовать одну огромную архитектурную схему.
Наоборот, одна и та же система показывается с нескольких точек зрения.
Можно представить это как карты.
Карта страны показывает крупные города и границы.
Карта города показывает районы и улицы.
Карта здания показывает этажи и помещения.
План комнаты показывает уже совсем другой уровень деталей.
С архитектурой происходит то же самое.
Например, на одном уровне достаточно показать:
Пользователь -> CRM -> Платёжный сервис
На следующем:
React SPA -> Django API -> PostgreSQL
Django API -> Redis
Django API -> RabbitMQ -> Celery Worker
Django API -> MinIO
А внутри Django можно показать:
Applications API -> Application Service -> Repository -> PostgreSQL
Document Service -> MinIO
Notification Service -> RabbitMQ
Это одна система, просто разный масштаб.
Почему нельзя показать всё одной диаграммой
Представим архитектурную схему, на которой одновременно находятся:
Пользователь
React
Nginx
Django
ApplicationViewSet
ApplicationService
ApplicationRepository
PostgreSQL
Redis
RabbitMQ
Celery
Docker
Kubernetes
Keycloak
MinIO
Payment Provider
Email Provider
Технически такая схема может быть правильной.
Но читать её почти невозможно.
Причина в том, что здесь смешаны разные уровни абстракции:
Пользователь - внешний участник
React - приложение
Django - приложение или технологическая основа приложения
ApplicationService - внутренний компонент
PostgreSQL - хранилище
Docker - среда выполнения
Payment Provider - внешняя система
C4 предлагает разделить эти вопросы.
Кто окружает систему? -> System Context
Из чего состоит система? -> Container
Из чего состоит отдельное приложение? -> Component
Где всё запускается? -> Deployment
Как проходит конкретный сценарий? -> Dynamic
Так каждая диаграмма отвечает на конкретный вопрос.
Базовая иерархия C4
Основные уровни можно представить так:
Software System -> Container -> Component -> Code
Здесь важно не путать термины C4 с привычными техническими терминами.
Особенно слово Container.
В C4 Container не означает Docker container.
Container - это отдельно запускаемое или разворачиваемое приложение либо хранилище данных.
Например:
React SPA
Django API
Celery Worker
PostgreSQL
Redis
RabbitMQ
MinIO
могут рассматриваться как Containers в C4.
А уже физически они могут быть запущены:
в Docker
на виртуальной машине
в Kubernetes
в облаке
на физическом сервере
Это другой уровень модели.
System Context Diagram
System Context Diagram - самый верхний уровень C4.
На нём система рассматривается как один объект.
Внутренняя структура пока неважна.
Основные элементы:
Person
Software System
External Software System
Relationship
Представим CRM образовательной программы.
В центре:
CRM System
Вокруг неё:
Applicant
Manager
Administrator
Education Platform
Payment Provider
Email Provider
Keycloak
Связи могут выглядеть так:
Applicant -> CRM System: подаёт и отслеживает заявку
Manager -> CRM System: проверяет заявки
Administrator -> CRM System: управляет программами и пользователями
CRM System -> Education Platform: передаёт данные участников
CRM System -> Payment Provider: создаёт и проверяет платежи
CRM System -> Email Provider: отправляет уведомления
CRM System -> Keycloak: выполняет аутентификацию пользователей
Уже по этой диаграмме можно понять:
- кто использует CRM;
- какие внешние системы существуют;
- какие основные интеграции необходимы;
- где заканчивается ответственность CRM.
При этом здесь пока не нужны:
PostgreSQL
Redis
Celery
ApplicationService
HTTP endpoints
database tables
Python classes
Они находятся слишком глубоко для Context Diagram.
Где провести границу системы
Это один из самых важных вопросов C4.
Например, Keycloak можно моделировать по-разному.
Если Keycloak является самостоятельной платформой идентификации, которой пользуются несколько систем организации, его логично показать как внешнюю Software System:
CRM System -> Keycloak
Если инфраструктура идентификации является частью рассматриваемого продукта и управляется той же командой, на Context Diagram она может находиться внутри более широкой системной границы.
То же относится к:
MinIO
RabbitMQ
аналитической платформе
внутреннему API gateway
C4 не даёт магического ответа, что всегда является "внутри".
Сначала нужно определить:
Какую систему мы сейчас описываем?
От ответа зависит граница диаграммы.
Что не нужно показывать на Context Diagram
Context Diagram не предназначена для внутренней архитектуры.
Поэтому здесь обычно не нужны:
Python classes
Django apps
database tables
REST endpoints
Celery tasks
Redis keys
Docker containers
Если на верхнем уровне появились десятки внутренних технических элементов, масштаб выбран неправильно.
Context Diagram должна позволять быстро ответить:
что это за система -> кто её использует -> с какими системами она взаимодействует
Container Diagram
После определения внешнего окружения можно приблизиться.
Container Diagram показывает основные исполняемые приложения и хранилища внутри Software System.
Для нашей CRM это может быть:
React SPA
Django API
PostgreSQL
Redis
RabbitMQ
Celery Worker
MinIO
Keycloak можно оставить внешней системой, если такая граница была выбрана на Context Diagram.
Теперь архитектура начинает выглядеть примерно так:
Applicant -> React SPA -> Django API -> PostgreSQL
Django API -> Redis
Django API -> Keycloak
Django API -> MinIO
Django API -> RabbitMQ -> Celery Worker
Celery Worker -> PostgreSQL
Celery Worker -> MinIO
Celery Worker -> Email Provider
Это уже один из самых полезных уровней для разработчиков.
По Container Diagram можно понять:
- какие приложения существуют;
- где хранится информация;
- какие приложения вызывают друг друга;
- где проходят синхронные и асинхронные взаимодействия;
- какие технологии используются;
- какие крупные зоны ответственности существуют.
Что такое Container в C4
В C4 Container - это приложение или хранилище, которое выполняет определённую архитектурную роль.
Например:
React SPA
Ответственность:
пользовательский интерфейс
Технология:
React + TypeScript
Django API
Ответственность:
HTTP API и основная бизнес-логика
Технология:
Python + Django + Django REST Framework
PostgreSQL
Ответственность:
основное долговременное хранение данных
Технология:
PostgreSQL
Redis
Ответственность:
кэш, временные данные или другие быстрые операции
Технология:
Redis
RabbitMQ
Ответственность:
передача сообщений между приложениями
Celery Worker
Ответственность:
выполнение фоновых и асинхронных задач
MinIO
Ответственность:
объектное хранение файлов
Хороший элемент C4 показывает не только название технологии, но и роль элемента.
Плохо:
PostgreSQL
Лучше:
Main Database
PostgreSQL
Хранит пользователей, заявки, программы и историю изменений
Технология не заменяет ответственность.
Container и Docker container - разные вещи
Это самая распространённая путаница в C4.
Представим C4 Container:
Django API
В production он физически может быть запущен как:
backend-1
backend-2
backend-3
три Docker container.
Но на Container Diagram это всё ещё:
Django API
один логический C4 Container.
И наоборот, один Docker Compose проект может содержать несколько C4 Containers:
web
worker
postgres
redis
rabbitmq
Поэтому:
C4 Container - логическая исполняемая часть системы
Docker container - конкретная технология изоляции и запуска процесса
Это совершенно разные уровни.
Что показывать в связи между контейнерами
Связи желательно подписывать.
Плохо:
React SPA -> Django API
Лучше:
React SPA -> Django API: выполняет HTTPS/JSON запросы
Плохо:
Django API -> PostgreSQL
Лучше:
Django API -> PostgreSQL: читает и изменяет данные CRM через SQL
Для RabbitMQ:
Django API -> RabbitMQ: публикует задания фоновой обработки
RabbitMQ -> Celery Worker: доставляет задания
Так архитектурная схема объясняет систему без необходимости угадывать смысл стрелок.
Component Diagram
Container Diagram показывает Django API как один архитектурный элемент.
Но сам backend может быть достаточно большим.
Тогда можно приблизить конкретный Container.
Например:
Django API
и показать его внутренние Components:
Applications API
Application Service
Document Service
Auth Integration
Notification Service
Reporting Service
Repositories
Возможное взаимодействие:
Applications API -> Application Service -> Application Repository -> PostgreSQL
Application Service -> Document Service -> MinIO
Application Service -> Notification Service -> RabbitMQ
Applications API -> Auth Integration -> Keycloak
Reporting API -> Reporting Service -> PostgreSQL
Теперь видно внутреннее устройство backend без погружения в отдельные Python-классы.
Что такое Component
Component в C4 - логически связанный набор функциональности внутри Container.
Например:
Application Service
может отвечать за:
- создание заявки;
- изменение заявки;
- проверку переходов State Machine;
- бизнес-правила;
- согласование.
Document Service:
- создание метаданных документа;
- работу с объектным хранилищем;
- выдачу ссылок;
- удаление файлов.
Notification Service:
- подготовку уведомлений;
- постановку задач в очередь;
- выбор шаблонов.
Главная идея:
Component должен иметь понятную ответственность.
Component и Python class - не одно и то же
Плохая Component Diagram:
ApplicationViewSet
ApplicationSerializer
ApplicationService
ApplicationRepository
ApplicationValidator
ApplicationMapper
ApplicationDTO
ApplicationPermission
Это уже почти структура файлов или классов проекта.
На архитектурной диаграмме такое количество деталей обычно мешает.
Вместо этого можно показать:
Applications API
Application Service
Application Repository
А уже внутри компонента Application Service могут существовать десятки классов и функций.
Поэтому:
Component - архитектурная ответственность
Class - элемент реализации
C4 Component Diagram не должна превращаться в файловое дерево проекта.
Когда нужен уровень Code
Четвёртый базовый уровень C4 - Code.
Он может показывать:
classes
interfaces
functions
packages
modules
Например, внутри Application Service:
ApplicationService
ApplicationRepository
ApplicationStateMachine
ApplicationValidator
Но этот уровень далеко не всегда нужно документировать отдельно.
Причина проста: код меняется быстрее архитектуры.
Если Class Diagram постоянно устаревает после каждого рефакторинга, ценность документации быстро падает.
Поэтому часто достаточно:
System Context
Container
Component
А код читается непосредственно в IDE.
Code Diagram имеет смысл там, где внутреннее устройство сложного компонента действительно требует отдельного объяснения.
Dynamic Diagram
Статические C4-диаграммы показывают:
что существует
Но иногда нужно понять:
что происходит во время конкретного сценария
Для этого используется Dynamic Diagram.
Например, сценарий:
Create Application
можно показать так:
1. Applicant -> React SPA: заполняет форму
2. React SPA -> Django API: POST /applications
3. Django API -> Keycloak: проверяет данные аутентификации
4. Django API -> PostgreSQL: сохраняет Application
5. Django API -> RabbitMQ: публикует задачу отправки уведомления
6. RabbitMQ -> Celery Worker: передаёт задачу
7. Celery Worker -> Email Provider: отправляет письмо
8. Django API -> React SPA: возвращает созданную Application
Здесь появляется порядок взаимодействия.
В этом смысле Dynamic Diagram близка к UML Sequence Diagram.
Разница скорее в общей методике и визуальном стиле.
Sequence Diagram детальнее формализует временное взаимодействие.
Dynamic Diagram C4 часто используется как более простой способ показать архитектурный сценарий с уже известными C4-элементами.
Когда использовать Dynamic Diagram
Она особенно полезна для сложных сценариев:
создание заказа
регистрация пользователя
обработка платежа
загрузка документа
асинхронное формирование отчёта
обработка webhook
Например, Container Diagram говорит:
Django API связан с RabbitMQ и Celery Worker
Но не объясняет, когда и зачем.
Dynamic Diagram показывает конкретный случай:
Generate Report -> Django API -> RabbitMQ -> Celery Worker -> MinIO -> Django API
Так архитектура становится связана с реальными use cases.
Deployment Diagram
Следующий вопрос:
Где физически запускаются эти Containers?
Для этого используется Deployment Diagram.
Здесь появляются:
Deployment Node
Container Instance
Infrastructure Node
Execution Environment
Представим небольшое deployment:
Internet -> Nginx -> backend replicas
backend replicas -> PostgreSQL
backend replicas -> Redis
backend replicas -> RabbitMQ
RabbitMQ -> worker replicas
worker replicas -> MinIO
Можно добавить уровень инфраструктуры:
Docker Host
Nginx
backend-1
backend-2
worker-1
worker-2
PostgreSQL
Redis
RabbitMQ
MinIO
Но здесь важно различать логический Container и runtime instance.
На Container Diagram:
Django API
На Deployment Diagram:
backend-1: Django API
backend-2: Django API
backend-3: Django API
То есть один логический Container имеет несколько запущенных экземпляров.
Container и Container Instance
Представим систему под нагрузкой.
Логическая архитектура:
React SPA -> Django API -> PostgreSQL
Deployment:
Nginx -> Django API instance 1
Nginx -> Django API instance 2
Nginx -> Django API instance 3
Все три instance реализуют один C4 Container:
Django API
Это позволяет не смешивать вопрос:
из каких приложений состоит система
с вопросом:
сколько экземпляров приложения сейчас запущено
Что можно показать на Deployment Diagram
Например:
Browser
Load Balancer
Virtual Machine
Docker Host
Kubernetes Cluster
Pod
Database Server
Object Storage
Внутри них размещаются экземпляры C4 Containers.
Например:
VM-1
Nginx
Django API instance 1
Django API instance 2
VM-2
Celery Worker instance 1
Celery Worker instance 2
DB Server
PostgreSQL
Теперь видно уже не только логическую архитектуру, но и эксплуатационную структуру.
C4 и Nginx
Nginx можно показывать по-разному в зависимости от уровня.
На Container Diagram он может вообще отсутствовать, если не является важной частью логической архитектуры.
Например:
React SPA -> Django API
может быть достаточно.
На Deployment Diagram уже имеет смысл показать:
Internet -> Nginx -> Django API replicas
потому что здесь важны routing, TLS termination и распределение запросов.
Это хороший пример основного принципа C4:
Один и тот же элемент может быть важен на одном уровне и не нужен на другом.
C4 и микросервисы
C4 часто показывают на примерах микросервисов, из-за чего возникает ложное впечатление:
C4 нужен только для microservice architecture.
Это неверно.
Монолит можно описывать ничуть не хуже.
Например:
Software System: CRM
Containers:
React SPA
Django Monolith
PostgreSQL
Redis
RabbitMQ
Celery Worker
MinIO
Внутри Django Monolith:
Applications Component
Programs Component
Users Component
Documents Component
Reporting Component
Notifications Component
Это обычная модульная монолитная архитектура.
C4 ничего не требует от способа реализации.
Она только помогает описать структуру.
Как будет выглядеть система после перехода на микросервисы
Допустим, со временем часть монолита была разделена.
Container Diagram может измениться:
React SPA
API Gateway
Application Service
Document Service
Notification Service
Reporting Service
PostgreSQL
RabbitMQ
MinIO
На System Context Diagram при этом может не измениться почти ничего:
Applicant -> CRM System
Manager -> CRM System
CRM System -> Payment Provider
Для пользователя CRM по-прежнему является одной системой.
Это наглядно показывает ценность уровней.
Архитектурная переработка внутри системы не обязательно меняет внешний Context.
Что именно показывать на каждом уровне
Удобно держать такую карту:
System Context -> пользователи, система, внешние системы
Container -> приложения, сервисы, базы и хранилища
Component -> крупные внутренние части конкретного приложения
Code -> классы и другие детали реализации
Dynamic -> взаимодействие элементов в конкретном сценарии
Deployment -> физическое размещение и runtime instances
Это позволяет сразу отсеивать лишние элементы.
Например:
Application table
не нужна на Container Diagram.
RabbitMQ
скорее всего, не нужен на System Context Diagram.
ApplicationSerializer
не нужен на Component Diagram.
Payment Provider
может не потребоваться на Code Diagram конкретного сервиса.
C4 и UML
C4 не пытается полностью заменить UML.
Они частично пересекаются.
Например:
C4 Component Diagram <-> UML Component Diagram
C4 Deployment Diagram <-> UML Deployment Diagram
C4 Dynamic Diagram <-> UML Sequence Diagram
Но C4 задаёт более простой архитектурный подход:
сначала Context -> потом Container -> потом Component
UML является намного более широкой нотацией и включает множество типов диаграмм.
На практике их можно использовать вместе.
Например:
C4 System Context -> граница системы
C4 Container -> архитектура приложений
C4 Component -> внутренние модули
UML Sequence -> сложный runtime-сценарий
ERD -> структура данных
BPMN -> бизнес-процесс
C4 и DFD
C4 показывает архитектурные элементы и отношения между ними.
DFD показывает движение данных.
Например, C4:
React SPA -> Django API -> PostgreSQL
DFD:
Applicant -> Application data -> Application Processing -> Application record -> Application Store
На C4 важен вопрос:
какие элементы системы существуют и как связаны
На DFD:
какие данные между ними проходят
В C4 связь тоже желательно подписывать, но она не заменяет полноценное моделирование потоков данных.
C4 и BPMN
BPMN показывает бизнес-процесс:
Подать заявку -> Проверить -> Согласовать -> Уведомить
C4 показывает архитектуру, которая этот процесс поддерживает:
React SPA -> Django API -> PostgreSQL
Django API -> RabbitMQ -> Celery Worker -> Email Provider
То есть:
BPMN -> что делает бизнес
C4 -> какие программные элементы обеспечивают это поведение
Из бизнес-процесса можно постепенно перейти к архитектуре.
C4 и ERD
ERD отвечает за структуру данных.
Например:
Student 1:N Application N:1 Program
C4 Container Diagram может показать только:
Django API -> PostgreSQL
Она не обязана раскрывать таблицы внутри PostgreSQL.
Если попытаться добавить в C4 Container Diagram:
students
applications
programs
documents
status_history
произойдёт смешивание уровней.
Для внутренней структуры PostgreSQL есть ERD.
Как построить C4 с нуля
Для новой системы удобнее двигаться сверху вниз.
1. Определить Software System
Сначала сформулировать:
Что именно мы моделируем?
Например:
CRM образовательной программы
Не:
вся инфраструктура компании
если именно она сейчас не является предметом анализа.
2. Определить пользователей
Например:
Applicant
Manager
Administrator
3. Определить внешние Software Systems
Например:
Keycloak
Payment Provider
Email Provider
Education Platform
4. Построить System Context
Получить:
Users -> CRM System -> External Systems
На этом уровне проверить границу системы.
5. Разложить систему на Containers
Например:
React SPA
Django API
PostgreSQL
Redis
RabbitMQ
Celery Worker
MinIO
6. Указать ответственность каждого Container
Не просто:
Redis
а:
Redis - хранит кэш и временные данные
7. Подписать отношения
Например:
React SPA -> Django API: HTTPS/JSON
Django API -> PostgreSQL: читает и изменяет основные данные
Django API -> RabbitMQ: публикует фоновые задания
RabbitMQ -> Celery Worker: доставляет задания
8. Выбрать сложный Container
Например:
Django API
и построить Component Diagram.
9. Для ключевых сценариев добавить Dynamic Diagram
Например:
Create Application
Upload Document
Generate Report
Process Payment
10. Для эксплуатации построить Deployment Diagram
Показать:
где запускаются Containers -> сколько существует instances -> как устроено сетевое взаимодействие
Общий путь получается таким:
граница системы -> окружение -> Containers -> Components -> runtime scenarios -> deployment
Насколько глубоко декомпозировать систему
Главная ошибка при построении архитектуры - считать, что больше деталей означает лучшую документацию.
Это не так.
Если Container Diagram содержит 60 элементов, вероятно, она перестала быть Container Diagram.
Если Component Diagram содержит каждый serializer и repository, она уже перестала быть архитектурной схемой.
Хорошая диаграмма должна отвечать на один вопрос.
Например:
Context -> кто окружает CRM?
Container -> из чего состоит CRM?
Component -> как устроен Django backend?
Dynamic -> что происходит при Create Application?
Deployment -> где всё запущено?
Если один рисунок пытается ответить сразу на все вопросы, он почти наверняка перегружен.
Подписывайте ответственность, а не только технологию
Плохой элемент:
Django
Он отвечает только на вопрос:
Какая технология используется?
Но не:
Зачем этот элемент существует?
Лучше:
CRM Backend
Django + DRF
Обрабатывает API-запросы и основную бизнес-логику CRM
Аналогично:
Background Worker
Celery
Выполняет долгие и асинхронные операции
или:
Object Storage
MinIO
Хранит загруженные документы и сформированные файлы
Архитектура описывает прежде всего ответственность.
Технология является дополнительной характеристикой.
Подписывайте связи
Плохая схема:
A -> B -> C -> D
Хорошая:
React SPA -> Django API: HTTPS/JSON
Django API -> PostgreSQL: SQL через ORM
Django API -> RabbitMQ: публикует задания
RabbitMQ -> Celery Worker: доставляет задания
Celery Worker -> Email Provider: отправляет email
Связь должна объяснять хотя бы:
зачем один элемент обращается к другому
а при необходимости ещё:
каким протоколом
Например:
Django API -> Keycloak: проверяет JWT через OIDC/JWKS
Ошибка: Container принимают за Docker container
C4 Container:
Django API
может иметь:
3 Docker containers
в production.
Это всё ещё один логический Container.
Docker относится к deployment.
Ошибка: Context Diagram превращают во внутреннюю архитектуру
Если на System Context находятся:
PostgreSQL
Redis
RabbitMQ
Celery
нужно проверить, действительно ли они являются отдельными внешними Software Systems.
Для обычной CRM они чаще относятся к внутренней архитектуре и должны появиться на Container Diagram.
Ошибка: Component Diagram превращают в список файлов
Плохо:
views.py
serializers.py
models.py
services.py
utils.py
permissions.py
Это структура исходного кода.
Component Diagram должна показывать архитектурные обязанности:
Applications API
Application Service
Document Service
Notification Service
Reporting Service
Ошибка: связи не подписаны
Если между компонентами просто проведены стрелки, читатель вынужден угадывать:
HTTP?
SQL?
event?
file upload?
dependency?
Подпись часто важнее самой линии.
Ошибка: технология указана вместо ответственности
Redis
RabbitMQ
PostgreSQL
Django
это список технологий.
Архитектурная модель должна объяснять:
что элемент делает
и только потом:
чем он реализован
Ошибка: слишком глубокая диаграмма
На Container Diagram не нужны Python-классы.
На Component Diagram не нужны все функции.
На Context Diagram не нужны внутренние базы данных.
Принцип простой:
каждый уровень показывает только детали своего масштаба
Ошибка: диаграмма не соответствует коду
Есть и обратная проблема.
Документацию нарисовали один раз при старте проекта, затем архитектура изменилась:
Redis больше нет
Notification Service вынесен
появился RabbitMQ
добавилась новая внешняя интеграция
а C4 осталась прежней.
Архитектурная схема полезна только тогда, когда ей можно доверять.
Поэтому лучше поддерживать небольшой набор действительно важных диаграмм, чем десятки подробных схем, которые невозможно обновлять.
Минимальный набор C4 для небольшого проекта
Для многих систем достаточно:
1 System Context Diagram
1 Container Diagram
несколько Component Diagram только для сложных Containers
несколько Dynamic Diagram для критичных сценариев
1 Deployment Diagram для production
Code Diagram часто вообще не требуется.
Например, для CRM:
System Context -> вся CRM и внешнее окружение
Container -> React, Django, PostgreSQL, Redis, RabbitMQ, Celery, MinIO
Component -> внутреннее устройство Django
Dynamic -> Create Application и Generate Report
Deployment -> Nginx, backend replicas, worker replicas, базы и хранилища
Такого комплекта уже достаточно, чтобы объяснить значительную часть архитектуры новому разработчику.
Что важно запомнить
C4 Model позволяет смотреть на одну архитектуру с разным масштабом.
Основная последовательность:
System Context -> Container -> Component -> Code
Дополнительные представления:
Dynamic -> поведение системы в конкретном сценарии
Deployment -> физическое размещение элементов
Главные вопросы уровней:
System Context - что это за система и кто её окружает?
Container - из каких приложений и хранилищ она состоит?
Component - из каких крупных частей состоит конкретное приложение?
Code - как компонент реализован в коде?
Dynamic - как элементы взаимодействуют в конкретном сценарии?
Deployment - где и в каком количестве всё запускается?
И самое важное различие:
C4 Container != Docker container
C4 Container является логическим архитектурным элементом.
Docker container является способом запуска приложения.
C4 не требует ни микросервисов, ни Docker, ни Kubernetes.
Ей одинаково можно описать:
монолит
модульный монолит
микросервисы
внутреннюю корпоративную систему
SaaS-платформу
небольшой web-сервис
Главная цель C4 не в том, чтобы нарисовать максимальное количество блоков.
Хорошая C4-документация позволяет последовательно ответить:
что за система -> кто её окружает -> из чего она состоит -> как устроены её части -> как проходит конкретный сценарий -> где всё это работает
Именно за счёт такого движения от общего к частному сложная архитектура становится понятной без одной гигантской схемы.