C4 Model

Меня сильно заинтересовали способы грамотной визуализации архитектуры программных систем, потому что диаграмы уровня [kafka] → [scala] → [postgresql] порядком поднадоели. Хочется выработать максимально информативный, но в тоже время удобный способ рисовать то, что мы проектируем.

Из того, что нашёл, больше всего понравился фреймворк C4 model. Но зачем вообще нужен целый фреймворк для визуализации? Без него каждый раз приходится импровизировать, что нарисовать на диаграмме. А нарисовать хочется многое: юзер-стори, технологии, карту микросервисов и хранилищ, технические ограничения… В итоге получается либо картинка с хаотичным набором стрелочек и квадратиков с перемешанными абстракциями “всё в одном”, либо фрустрация и рисование примитивной схемы а-ля “ну тут сервис, тут база, всё понятно вроде”.

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

  1. Контекст. Верхнеуровневый взгляд на всю систему в целом, и то, как она взаимодействует с другими целостными программными продуктами (например, сторонние CRM или решения для эквайринга). На этом уровне обязательно фигурирует пользователь и его основная цель взаимодействия с программой. Диаграма должна выглядеть настолько просто, чтобы её можно было показать нетехническим специалистам.
  2. Контейнеры. Контейнер — это изолированная единица рантайма: серверное или клиентское приложение, база данных, очередь сообщений. Здесь нужно погрузиться внутрь системы и крупноблочно отобразить её ключевые составляющие. Какие есть клиентские приложения, как они взаимодействуют с сервером, в каких базах лежат самые ценные данные. Можно выделить несколько групп контейнеров по сценариям использования, если их слишком много для одной диаграммы.
  3. Компоненты. Компонент — это уже логическая единица внутри контейнера. Здесь контейнер декомпозируется на набор функциональных единиц с описанием их ответственности и связности друг с другом. Например, если контейнер — сервис с учётными записями пользователей, то в качестве компонент можно отобразить модули аутентификации, управления правами, регистрации, поиска и редактирования.
  4. Код. Тут можно нарисовать классический UML со связями внутри кода.

Мне нравится подход, но с парой ремарок:

  • Я бы сократил C4 до C3. Визуализация связей внутри кода приложения кажется избыточной: если все сервисы пишутся по единым паттернам в неком подобии гексагональной архитектуры, то и связи между модулями будут типовыми. Лучше инвестировать в выработку организационных стандартов кодирования, чем в рисование UML.
  • В микросервисных реалиях одно приложение содержит в себе совсем немного компонент, поэтому на третьем уровне вместо статической диаграммы внутренностей отдельного приложения лучше нарисовать основные процессы, которые оно выполняет. Для этого хорошо подходит диаграмма последовательности из PlantUML.
  • Описание слоёв не является догмой и должно адаптироваться под нужды организации или команды.

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