На одном из проектов мы хотели попробовать использовать C4 модели для описания архитектуры приложения. Посмотрели разные инструменты (Structurizr, C4-PlantUML, IcePanel, ...), нам не зашло и решили сделать свой инструмент моделирования. В этой статье я расскажу что и как у нас получилось.

Почему не подошли существующие инструменты:

  • Хотелось бы, чтобы модели можно было описывать текстом, но при этом была возможность подвигать фигуры на диаграмме вручную. Пока для C4 у нас только диаграммный редактор и подвигать фигуры можно, но текстовый редактор скорее всего будет только в следующей статье

  • Хотелось бы удобный древовидный навигатор по моделям. Я думаю, это получилось

  • Хотелось бы поддержку не только C4, но и других видов моделей (данные, процессы, требования, ...). Сейчас есть модели классов, EPC, VAD и при необходимости можно добавлять новые нотации

  • Хотелось бы, чтобы модели соответствовали международным стандартам моделирования и не были вещью в себе. Это получилось, у нас модели соответствуют стандарту OMG MOF и могут использоваться в любых других инструментах, которые так же реализуют этот стандарт

  • Хотелось бы генерировать документы и код по моделям, преобразовывать модели, автоматизировать разную рутину. Частично реализовали, но пока только для продвинутых пользователей

  • Хотелось бы полноценный репозиторий моделей с управлением доступом, версионированием, API. Получилось, но пока без версионирования

  • Хотелось бы описывать архитектурные правила для валидации C4 и других моделей. Это пока не сделали

  • Хотелось бы чтобы всё это было бесплатно и без искусственных ограничений на сложность моделей и т. д. Это есть

  • Хотелось бы развернуть репозиторий локально внутри компании. Есть Docker образы

  • Хотелось бы Single Sign‑On и в целом возможность встраивания в ландашафт информационных систем компании. Single Sign‑On поддерживается через Keycloak или аналогичную систему, а для интеграции есть API

Архитектура нашего приложения на C4

Немного опишу нотацию C4 на случай если вы не сталкивались с ней раньше. Но чтобы это не было очередное руководство в стиле «добавили несколько квадратиков, смотрите какая замечательная архитектура получилась», попробую применить всё это к архитектуре нашего собственного приложения и сформулировать комментарии и вопросы, которые при этом возникали.

C4 — это метод описания архитектуры приложений. Он позволяет всем участникам проекта понять что за приложение разрабатывается, кто будет им пользоваться, с какими другими системами оно будет взаимодействовать. Также C4 позволяет провалиться в детали реализации: это монолитное или микросервисное приложение, какие технологии используются и т. д.

По ссылке доступен проект с описанием архитектуры нашего приложения. В предыдущих статьях можно посмотреть описание инструмента в целом, как в нём работать с моделями.

Диаграммы контекста (уровень 1)

При использовании подхода C4 первое что вы делаете это описываете контекст использования вашего приложения:

Диаграмма контекста
Диаграмма контекста

На скриншоте:

  • Слева — древовидный навигатор по модели: системы содержат контейнеры, которые содержат компоненты

  • Справа — форма свойств: у корневого объекта (ландшафт информационных систем) два атрибута (название и описание), у других объектов могут быть дополнительные атрибуты (например, используемые технологии, вид контейнера и т. д.)

  • По центру — редактор диаграмм

На диаграмме контекста описывается следующее:

  • Разрабатываемая система (синий прямоугольник)

  • Пользователи системы (человечки):

    • Разработчики метамоделей определяют правила моделирования

    • Разработчики моделей создают модели

    • Бизнес‑пользователи используют модели

  • Сторонние системы, с которыми наше приложение будет интегрироваться (серые прямоугольники):

    • Система управления учётными данными пользователей. У нас это Keycloak

    • Поставщики моделей. Например, 1С может предоставлять модель организационной структуры предприятия

    • Потребители моделей. Например, система исполнения процессов может получать из инструмента моделирования модели процессов

Диаграммы контейнеров (уровень 2)

На втором уровне проваливаемся внутрь разрабатываемой системы:

Диаграмма контейнеров
Диаграмма контейнеров

На диаграмме контейнеров описывается следующее:

  • Само приложение изображаем пунктирной линией. Причём в репозитории (или в навигаторе по моделям) информационная система это физически один объект, просто на разных диаграммах (на уровне 1 и на уровне 2) он изображается по‑разному

  • Внутри системы показываем контейнеры, из которых она состоит. Каждый контейнер — это отдельно развертываемая и запускаемая часть приложения. Часто пишут, что их не нужно путать с Docker контейнерами, но в нашем случае они совпадают. На мой субъективный взгляд эта схема выглядит слишком технической, мне хотелось бы описать сначала функциональные блоки (например, подсистема управления метамоделями, редактор моделей, подсистема управления доступом, подсистема хранения моделей, подсистема версионирования моделей и т. д.), затем для каждого функционального блока описать функции, которые он позволяет выполнять. Но вместо этого мы сразу проваливаемся в технику — в 3-уровневую архитектуру. В принципе, так и задумано, это назначение архитектурных моделей. Но лично мне сначала хотелось бы увидеть более верхнеуровневые модели, ощущение что одного C4 недостаточно. Контейнеры изображаются синими прямоугольниками:

    • Веб‑интерфейс

    • API сервер

    • База данных

  • Снаружи системы показываем пользователей. Мне не хотелось снова дублировать все 3 категории пользователей на этой диаграмме. Можно было бы добавить нового обобщенного пользователя, но на уровне 1 его не было и довольно странно, если бы он вдруг появился на уровне 2. Видимо с пользователями та же история что и с контейнерами. Нужно разбивать их на категории исходя не из бизнес‑смысла, а из того с какими контейнерами они взаимодействуют? Если с одним и тем же, значит уже на уровне 1 должен быть только один пользователь?

  • Снаружи системы показываем внешние системы с уровня 1 (это те же самые объекты, которые можно перетащить на диаграмму из навигатора). Для них мы можем описать уже более детальные связи, с какими именно контейнерами они взаимодействуют

Диаграммы компонентов (уровень 3)

На третьем уровне проваливаемся внутрь контейнеров.

Компоненты фронтенда:

Диаграмма компонентов фронтенда
Диаграмма компонентов фронтенда

Компоненты бэкенда:

Диаграмма компонентов бэкенда
Диаграмма компонентов бэкенда

На диаграмме компонентов описывается следующее:

  • Исходный контейнер изображаем пунктирной линией

  • Внутри показываем компоненты в виде синих прямоугольников. Есть разные мнения по поводу того что такое компонент. Они могут быть разбиты по организационным единицам кода (jar, dll, assembly, folder,...) или нет. В нашем приложении организационные единицы выделены вполне осмысленно и они могли бы изображаться как компоненты, но как на одной диаграмме показать сотню компонентов?.. В руководствах по C4 обычно приводятся примеры ещё более мелких компонентов (контроллеры, сервисы, репозитории) — да, их тысячи хоть в сколько‑нибудь крупном приложении! Как их все показать на диаграмме? В итоге, я нарисовал какие‑то компоненты выше, но без удовольствия

  • Также на всех уровнях можно группировать объекты

  • Снаружи показываем другие контейнеры

Диаграммы кода (уровень 4)

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

На этом уровне у нас модель данных. Вот, основные сущности:

Модель данных
Модель данных

И базовые сущности:

Базовые сущности
Базовые сущности

Модель данных может быть удобно редактировать в текстовом виде:

Текстовый редактор для модели данных
Текстовый редактор для модели данных

У нас достаточно богатая платформо независимая система типов, чтобы генерировать из одной модели SQL скрипты, Java код и т. д. Также поддерживается локализация, чтобы по модели можно было генерировать документацию (если вы откроете ссылку в фоновой вкладке, то Mermaid диаграмма может не сгенерироваться сразу, в этом случае можно обновить страницу, пока не разобрались в чём причина):

Документация, сгенерированная по модели данных
Документация, сгенерированная по модели данных

На скриншоте выше Mermaid‑диаграмма, сгенерированная по модели данных. И она гораздо менее читаемая, чем диаграмма в начале этого раздела. Конечно в будущем в документы нужно будет вставлять исходные диаграммы.

Как это сделано

Метамодель

Чтобы добавить новый язык моделирования нужно описать для него метамодель. К сожалению готовой метамодели не было, поэтому мы смотрели справочник по Structurizr DSL и для основных понятий создали метаклассы:

Иерархия типов объектов в C4
Иерархия типов объектов в C4

На уровне метамодели можно было бы не запариваться с правилами вложенности, что система состоит из контейнеров, которые состоят из компонентов. Метамодель можно было бы сделать более свободной, а вложенность уже валидировать отдельно. Но на этот случай есть такой удобный паттерн:

Правила вложенности объектов в C4
Правила вложенности объектов в C4

Например, есть интерфейс «Владелец объектов внутри информационной системы» (SoftwareSystemItemOwner). Это может быть:

  • Информационная система (SoftwareSystem)

  • Группа контейнеров (ContainerGroup)

И есть другой интерфейс «Элемент информационной системы» (SoftwareSystemItem). Это может быть:

  • Группа контейнеров (ContainerGroup)

  • Контейнер (Container)

Группа контейнеров упомянута в обоих списках. Это позволяет добавлять в модель произвольное количество уровней вложенности для групп контейнеров. Можете добавлять контейнеры сразу в информационную систему, а можете добавить несколько штук вложенных групп и уже туда добавить контейнер.

Отдельная тема как хранить связи между объектами в моделях с несколькими уровнями вложенности. Представьте, что у вас в BPMN две дорожки, в каждой по одному объекту, которые связаны между собой. Какой из дорожек должна принадлежать связь? Чтобы не запариваться с этим обычно связи лежат в корне модели. А что если связаны два объекта внутри одной дорожки? Вроде логично и связь хранить в ней же. А что если мы потом перетащим один из объектов или оба в другую дорожку? Словом, и такие связи обычно тоже хранятся в модели на верхнем уровне. Но для C4 такой подход не работает, в нём слишком много уровней вложенности, и если все связи вытаскивать в корень, то там будет хаос. Поэтому на уровне метамодели у нас определено несколько типов объектов кроме корневого ландшафта информационных систем, в которых могут храниться связи:

Контейнеры для связей в C4
Контейнеры для связей в C4

Такая метамодель уже достаточно формальная в отличие от исходного описания. Её можно продвигать в качестве стандарта по аналогии с BPMN, UML, SysML, ... Можно использовать в разных инструментах моделирования, соответствующих стандарту OMG MOF. Да, и в принципе, если модель соответствует достаточно строгой метамодели, то по ней удобно генерировать документы, код, выполнять разные методы анализа.

Правила отображения объектов на диаграмме

Для C4 у нас три типа фигур:

Виды фигур в C4
Виды фигур в C4

Для каждого класса объектов может быть задана базовая фигура. А ещё в зависимости от значений атрибутов объекту могут назначаться динамические (условные) классы. Например, у контейнера может быть вид «не определен» (в этом случае он отображается как прямоугольник) или «база данных» (в этом случае он отображается как цилиндр). Ещё есть признак это уже существующий контейнер (в этом случае он отображается серым цветом) или новый (в этом случае он отображается синим цветом). Всего возможно 4 комбинации: синие прямоугольники, синие цилиндры, серые прямоугольники, серые цилиндры. А вообще их могло бы быть и больше. Например, для связей в моделях классов уже 6 комбинаций по направлению связи (прямая или обратная) и по виду (ассоциация, композиция или агрегация). Очень удобно, что не нужно для каждого варианта рисовать отдельную картинку:

Атрибуты, которые влияют на правила отображения контейнеров в C4
Атрибуты, которые влияют на правила отображения контейнеров в C4

Достигается это следующим образом. В каждом SVG с помощью CSS-классов указывается значения каких визуальных атрибутов можно менять:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 200 100"
     width="200" height="100" preserveAspectRatio="none">
  <g class="fill stroke stroke-width stroke-dasharray"
     fill="white" stroke="black" stroke-width="1">
    <path d="M 3 13 V 87 A 97 10 0 0 0 197 87 V 13"
          vector-effect="non-scaling-stroke" />
    <ellipse cx="100" cy="13" rx="97" ry="10"
             vector-effect="non-scaling-stroke" />
  </g>
</svg>

Заключение

В статье мы немного рассказали про C4. Вообще по нему более чем достаточно руководств, но возможно у вас при его использовании возникают такие же вопросы как и в этой статье. И вы можете поделиться своей болью или успехом.

Также мы рассказали про метамодель C4, про подходы, которые можно использовать для моделей с несколькими уровнями вложенности. Если вы разрабатываете инструменты моделирования, то возможно нашли для себя что‑то интересное или хотите чем‑то поделиться. Если вы считаете, что в тексте слишком много рекламы и слишком мало пользы, то, пожалуйста, разверните это немного, чтобы мы понимали как улучшить статьи.

Комментарии (8)


  1. serginfo2009
    27.08.2025 06:41

    А чем конкретно Structirizr не устроил?

    Мы у себя внедрили, и, если его правильно приготовить, то он может очень многое.


    1. Ares_ekb Автор
      27.08.2025 06:41

      Нельзя поправить диаграммы, они очень корявыми получались. Хочется, чтобы модели редактировались и в коде, и чтобы можно было подвигать фигуры на диаграмме при необходимости

      Кроме C4 нам нужно много других моделей для описания требований, функциональных подсистем, сценариев использования, структур данных и т. д.

      Не очень удобный интерфейс, хотелось древовидный навигатор по всем моделям и объектам

      У Structurizr сложный тулинг. Как, например, генерить документы?.. И в целом это вещь в себе. Для инструментов моделирования есть много стандартов и готовых инструментов, а в Structurizr всё это игнорируется, у них свой формат хранения моделей, нельзя использовать готовые инструменты для генерации документов по этим моделям или для их анализа

      Нет управления доступом к моделям. Что если проектов много? Хотя Structurizr модели можно хранить в Git рядом с кодом. Но хотелось бы централизованный архитектурный репозиторий

      Хотелось бы описать архитектурные правила (для именования сущностей и связей, правила типа не больше N фигур и не больше M связей на диаграмме и т. д.) и потом валидировать по ним модели

      В целом всё это наверное достаточно специфические требования. Я думаю, что есть много проектов, где Structurizr вполне норм


      1. serginfo2009
        27.08.2025 06:41

        Так а там можно руками править. Автолейаут отключили, и вперёд.

        Другие модели поддерживаются встроенными plantunl / kroki из коробки.

        Правила натягиваются скриптами, поддержка которых есть, опять же, из коробки.

        По остальному, наверное, более-менее соглашусь.


        1. Ares_ekb Автор
          27.08.2025 06:41

          Точно можно править! Спасибо, я упустил этот момент или забыл уже

          PlantUML всё равно не закрывает все требования. Например, нам нужны в модели данных платформо независимые типы (number, string,...) с разными параметрами (количество знаков после запятой, максимальная длина, шаблон для строки,...), чтобы потом по этим моделям генерировать SQL скрипты (при этом типы преобразуются в типы для конкретной СУБД — varchar, decimal,...), генерировать Java‑код (здесь типы будут заменяться уже на другие). Или нам для сущностей в модели данных нужно два названия (техническое на английском языке и на русском языке), чтобы можно было генерировать документацию

          Или, например, для описания требований к системе в PlantUML нет нотации. Плюс PlantUML не позволяет двигать фигуры. Не позволяет делать межмодельные ссылки

          С одной стороны, есть инструменты типа Structurizr, PlantUML и т. д., которые позволяют с минимальными усилиями закрыть требования. С другой стороны, есть более сложные инструменты моделирования типа Archi, Enterprise Architect, Rational Sofrtware Architect Designer и т. д. Мы хотим сделать что‑то среднее. Чтобы эта штука была простой и бесплатной, но по функциональности не сильно уступала Enterprise решениям

          Да, и в конце концов, наличие аналогичных проектов для меня это скорее признак, что на такой продукт есть спрос, чем повод не делать этот проект, я уверен, что у нас во многом получится лучше


        1. olku
          27.08.2025 06:41

          Еще Structurizr можно форкнуть, у него простой исходный код, и прикрутить что Саймон прикручивать не желает, например, arc42, превью и дополнительные АПИ. Для компаний делал импорт схем из баз данных и объектов из Кубера и Сворм кластеров. Двигать компоненты можно локально, координаты сохраняются и не пропадают при следующем импорте. Результат упаковывается в докер и релизится на сайт документации. Единственный минус Structurizr это рендеринг C4 на клиенте.


          1. Ares_ekb Автор
            27.08.2025 06:41

            Очень интересно! А в какие модели импортировали схемы данных? В PlantUML? И что импортировали из Кубера? Модели для DevOps? Им эти модели были нужны, чтобы просто собрать информацию о своём ИТ ландшафте или потом они правили модели и что-нибудь генерировали из них?


            1. olku
              27.08.2025 06:41

              Class diagrams PlantUML для схем. Кластеры, стеки/неймспейсы, ингресс, сервисы и сетевые политики из оркестратора в Structurizr DSL. Потребителей несколько - архитекторы, разработчики, SRE. Обновляются после деплоя. Так как это Architecture as Code, фитнесс функциями проверяется соответствие ADR, да и вообще удобно анализировать и встраивать вьюхи в Readme.


  1. olku
    27.08.2025 06:41

    Пару лет назад рассматривали IcePanel, его два другана фаундера пилят. Но они заломили за enterprise несколько десятков тысяч долларов.