Что такое диаграмма модели C4?
Библиотека диаграмма модели C4 — иерархическая четырехуровневая архитектурная структура, разработанная для документирования архитектуры программного обеспечения с различной степенью детализации. Созданная Саймоном Брауном, модель C4 избегает неясных блоков и линий, структурируя карты систем по четырем четким уровням абстракции: Контекст (область применения на уровне системы), Контейнер (приложения и хранилища данных), Компонент (внутренние модули), и Код (реализации на уровне классов).
Для эффективной реализации этой модели в тексте инженеры используют официальное расширение библиотеки C4-PlantUML стандартной библиотеки. Эта библиотека заменяет обычные формы UML специализированными макросами, которые автоматически вставляют различные цвета, формы и поля метаданных для пользователей, систем и баз данных. С помощью VPasCode, вы можете чисто определять эти вложенные среды в коде. Двигатель компоновки динамически направляет векторы соединений и масштабирует текстовые поля, не нарушая геометрию вашего макета.
Руководство по основному синтаксису: элементы и конструкции
Построение корректной модели C4 с помощью PlantUML зависит от импорта правильных файлов библиотеки, выбора структурных макросов, установки границ и использования специализированных связей отношений.
1. Импорт файлов стандартной библиотеки C4
Библиотека C4-PlantUML расширение разбито на отдельные файлы, которые напрямую соответствуют различным уровням абстракции модели. Чтобы избежать замедления производительности или ошибок компилятора, вы должны импортировать только тот файл, который соответствует уровню, на который ориентирована ваша диаграмма:
@startuml
' Включите требуемый файл слоя C4
!include <C4/C4_Context>
' Используйте C4_Container или C4_Component для более глубоких архитектурных карт
2. Объявление основных акторов и систем (уровень контекста)
На высоком уровне контекста системы вы моделируете внутренние компоненты, внешние зависимости и конечных пользователей. Стандартная библиотека предоставляет специфические макросы, которые принимают идентификатор, визуальную метку и необязательную описательную метку:
Person(id, "Метка", "Описание")— представляет профиль человека-пользователя или актора системы.System(id, "Метка", "Описание")— Представляет основную внутреннюю программную экосистему приложения или сервиса.System_Ext(id, "Метка", "Описание")— Представляет внешнюю систему или зависимость от стороннего API (отображается в явной серой цветовой палитре).
@startuml C4_Elements
!include <C4/C4_Context>
Person(customer, "Клиент банка", "Клиент с личным банковским счетом")
System(banking_sys, "Основная банковская система", "Обрабатывает финансовые операции")
System_Ext(mail_sys, "Служба электронной почты", "Внутренний шлюз уведомлений SMTP") 
3. Расширение границ (уровни контейнера и компонента)
Когда вы углубляетесь в уровень контейнера, вы моделируете веб-приложения, микросервисы и базы данных. Вы можете изолировать эти внутренние элементы внутри явной логической границы, используя обертку макросаSystem_Boundary() макрос-обертку:
!include <C4/C4_Container>
System_Boundary(c1, "Экосистема электронной коммерции") {
Container(web_app, "Одностраничное приложение", "React & TypeScript", "Предоставляет пользовательские функции через веб-интерфейс")
ContainerDb(database, "Реляционная база данных", "PostgreSQL", "Хранит профили пользователей и истории бухгалтерских записей")
} 
4. Отображение технических взаимосвязей
Вместо использования простых штриховых линий, C4 использует явный формат макросов для общения, какRel(Идентификатор_Источника, Идентификатор_Получателя, "Метка", "Технология"). Это делает ваши архитектурные схемы легко читаемыми, поскольку каждое соединение должно указывать свою цель и используемый транспортный протокол (например, HTTPS, gRPC или AMQP):
!include <C4/C4_Container>
Person(customer, "Клиент банка", "Клиент с личным банковским счетом")
System(banking_sys, "Основная банковская система", "Обрабатывает финансовые операции")
System_Ext(mail_sys, "Служба электронной почты", "Внутренний шлюз уведомлений SMTP")
System_Boundary(c1, "Экосистема электронной коммерции") {
Container(web_app, "Одностраничное приложение", "React & TypeScript", "Предоставляет пользовательские функции через веб-интерфейс")
ContainerDb(database, "Реляционная база данных", "PostgreSQL", "Хранит профили пользователей и истории бухгалтерских записей")
}
Rel(customer, web_app, "Использует функции магазина через", "HTTPS")
Rel(web_app, database, "Читает и записывает транзакционные данные через", "SQL/TCP") 
Лучшие практики для читаемых архитектур C4
- Никогда не смешивайте уровни абстракции: Держите ваши диаграммы сосредоточенными на одном уровне. Не смешивайте детализированные внутренние программные компоненты с высоким уровнем диаграммы контекста системы. Если система становится слишком сложной, разбейте ее на отдельную диаграмму уровня контейнера.
- Явно определяйте технологии: Всегда используйте четвертый параметр в вашем
Rel()макросах, чтобы указать точную технологию или протокол, используемый (например,"JSON/HTTPS"или"JDBC"). Это дает вашей команде важный контекст реализации при первом взгляде. - Используйте переопределения направления компоновки: Если ваши компоненты начинают неправильно располагаться, используйте макросы направления отношений (например,
Rel_D()для вниз,Rel_R()для вправо, илиRel_L()для влево) для ручной настройки архитектурного потока.
Реальные примеры PlantUML C4
Пример 1: Макет контекста системы высокого уровня (уровень 1)
Этот функциональный чертеж моделирует стандартную диаграмму контекста системы уровня 1, описывая, как клиент взаимодействует с интернет-банкинг-приложением и его внешними зависимостями.
@startuml
!include <C4/C4_Context>
title Диаграмма контекста системы для интернет-банкинг-системы
Person(customer, "Личный клиент банка", "Клиент банка с личными счетами.")
System(banking_system, "Интернет-банкинг-система", "Позволяет клиентам просматривать финансовую информацию и совершать переводы.")
System_Ext(mail_system, "Подсистема электронной почты", "Внутренний корпоративный кластер серверов электронной почты SendGrid.")
Rel(customer, banking_system, "Использует онлайн-панель через")
Rel_R(banking_system, mail_system, "Отправляет оповещения и коды подтверждения с помощью", "SMTP")
@enduml 
Разбор синтаксиса: Эта диаграмма сосредоточена исключительно на высоком уровне. Макрос System_Ext автоматически применяет серый цветовой профиль к службе электронной почты, визуально отделяя основную систему от внешних зависимостей. Макрос Rel_R заставляет движок компоновки разместить узел электронной почты непосредственно справа от блока банковской системы.
Пример 2: Глубокий анализ топологии контейнеров микросервисов (уровень 2)
Этот продвинутый корпоративный чертеж разбивает систему на составляющие контейнерные приложения и изолированные хранилища данных, показывая, как веб-трафик проходит через шлюз API до микросервисов на стороне сервера.
@startuml
!include <C4/C4_Container>
title Диаграмма контейнеров для шлюза платежного портала
Person(merchant, "Веб-партнер-продавец", "Интегрирует конечные точки платформы для оформления заказов на своих веб-сайтах.")
System_Boundary(portal_scope, "Экосистема шлюза платежей") {
Container(api_gateway, "Прокси маршрутизации API", "Nginx", "Перехватывает входящие вызовы, обрабатывает лимиты скорости и балансирует узлы.")
Container(auth_service, "Микросервис идентификации", "Go & OAuth2", "Проверяет токены API и области доступа разработчиков.")
Container(txn_service, "Журнал транзакций", "Java Spring Boot", "Обрабатывает платежи и управляет счетами в журнале.")
ContainerDb(ledger_db, "Хранилище данных журнала", "CockroachDB", "Реализует распределенные схемы таблиц, соответствующие ACID.")
}
' Поток трафика проходит чисто через внутренние целевые контейнеры
Rel(merchant, api_gateway, "Отправляет платежные данные через", "HTTPS/JSON")
Rel_D(api_gateway, auth_service, "Проверяет входящие токены через", "gRPC")
Rel_D(api_gateway, txn_service, "Перенаправляет действия оформления заказа на", "gRPC")
Rel_R(txn_service, ledger_db, "Сохраняет записи журнала через", "SQL/TLS")
@enduml 
Разбор синтаксиса: Используя System_Boundary макрооболочку, внутренние компоненты аккуратно группируются внутри четко обозначенной рамки. Специализированная ContainerDb макрос отображает хранилище данных с явным иконкой цилиндра базы данных, что делает разделение между вычислительными средами выполнения и слоями постоянного хранения данных очевидным при первом взгляде.