Материал учебного циклаОткрытый материал

C4 Model: архитектура программной системы

Практическое введение в C4 Model для описания архитектуры информационных систем. Разбираем уровни System Context, Container и Component, дополнительные Dynamic и Deployment Diagram, границы между ними и применение C4 для монолитов и микросервисов.

Продукт и интерфейсы #C4 Model #UML #архитектура
Учебный цикл Моделирование и проектирование информационных систем Материал 6 из 9

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-документация позволяет последовательно ответить:

что за система -> кто её окружает -> из чего она состоит -> как устроены её части -> как проходит конкретный сценарий -> где всё это работает

Именно за счёт такого движения от общего к частному сложная архитектура становится понятной без одной гигантской схемы.

Продолжить

  1. 01 BPMN: от бизнес-процесса до требований к системе Что такое BPMN, зачем моделировать бизнес-процессы и как читать простую диаграмму от начала до результата.
  2. 02 UML: как описывать программную систему с разных сторон Введение в UML и основные виды диаграмм. Разбираем, зачем одной системе нужны разные представления, что показывают Use Case, Sequence, Class, Activity, State Machine, Component и Deployment Diagram и как выбрать подходящую диаграмму под задачу.
  3. 03 ERD и моделирование данных Подробное введение в ERD и моделирование данных. Разбираем сущности, атрибуты, первичные и внешние ключи, связи 1:1, 1:N и M:N, обязательность связей, нормализацию и переход от ERD к PostgreSQL и Django ORM.
  4. 04 State Machines: жизненный цикл сущностей Практическое введение в State Machine и моделирование жизненного цикла сущностей. Разбираем состояния, переходы, события, guard conditions, побочные эффекты и связь State Machine с BPMN, базой данных и API.
  5. 05 DFD: как данные проходят через систему Практическое введение в DFD и моделирование потоков данных. Разбираем внешние сущности, процессы, хранилища и потоки данных, Context Diagram, уровни декомпозиции, баланс между уровнями, связь DFD с API, безопасностью, BPMN и Sequence Diagram.
  6. 06 API Contracts: как системы договариваются о взаимодействии Практическое руководство по проектированию API-контрактов. Разбираем структуру HTTP API, ресурсы и action endpoints, request и response schemas, ошибки, OpenAPI, версионирование, совместимость, аутентификацию, авторизацию, webhook-контракты и безопасное изменение API для существующих consumers.
  7. 07 Event-Driven Modeling: события, очереди и асинхронные процессы Практическое руководство по Event-Driven Modeling и проектированию асинхронных взаимодействий. Разбираем команды и события, Producer, Broker и Consumer, очереди и routing, идемпотентность, порядок событий, retries, Dead Letter Queue, Transactional Outbox, eventual consistency и связь событий с BPMN и State Machine.
  8. 08 Как собрать BPMN, UML, ERD, C4 и API в одну проектную документацию Практическое руководство по сборке проектной документации информационной системы. Показываем, как связать BPMN, UML, ERD, State Machine, DFD, C4, API Contracts и Event-Driven Modeling так, чтобы каждая модель отвечала на свой вопрос и не дублировала остальные.

Обратная связь

Материал был полезен?

Нашли ошибку или неточность? Сообщить →

Начните вводить — найдём материал по всей библиотеке.