Добавить в корзинуПозвонить
Найти в Дзене
PurpleSchool

Руководство по нотациям описания архитектуры приложения

Как технический директор, я регулярно обсуждаю с командой архитектуру сервисов. И каждый раз сталкиваюсь с одной проблемой — отсутствием единого подхода к визуализации архитектурных решений. Даже при использовании Miro или доски с маркером схемы превращаются в набор случайных фигур: квадратиков, кругов, стрелок. Каждый рисует по-своему. В результате — разный смысл, лишние пояснения и потеря времени. Тогда я взял цель создать общий язык визуализации архитектуры — простой, однозначный и понятный всем участникам команды. К концу статьи вы освоите простую в использовании нотацию, которую можно использовать в draw.io, visio или другом удобном инструменте. А также, я подготовил для вас полностью готовое решение — библиотеку в Figma и оставил полезный блок бесплатных материалов для изучения разработки. Во-первых — диаграмма классов. Она удобна для анализа уже существующего кода, но не применима для изначального проектирования, где мы оперируем более верхнеуровневыми объектами. Еcть и c4model,
Оглавление

Как технический директор, я регулярно обсуждаю с командой архитектуру сервисов. И каждый раз сталкиваюсь с одной проблемой — отсутствием единого подхода к визуализации архитектурных решений. Даже при использовании Miro или доски с маркером схемы превращаются в набор случайных фигур: квадратиков, кругов, стрелок. Каждый рисует по-своему. В результате — разный смысл, лишние пояснения и потеря времени.

Тогда я взял цель создать общий язык визуализации архитектуры — простой, однозначный и понятный всем участникам команды. К концу статьи вы освоите простую в использовании нотацию, которую можно использовать в draw.io, visio или другом удобном инструменте. А также, я подготовил для вас полностью готовое решение — библиотеку в Figma и оставил полезный блок бесплатных материалов для изучения разработки.

А что есть сейчас?

Во-первых — диаграмма классов. Она удобна для анализа уже существующего кода, но не применима для изначального проектирования, где мы оперируем более верхнеуровневыми объектами. Еcть и c4model, которая ближе к теме и предлагает 4 уровня детализации схемы ПО. Отлично подходит для верхнего уровня описания системы, но при детализации на компоненты не имеет детальных стандартов.

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

  • Позволять описывать отделимые части системы на верхнем уровне, которые далее я буду назвать «компоненты»;
  • Описывать зависимости и поток вызовов с помощью связей, по котором сразу будет видно наличие архитектурных ошибок;
  • Подходить как для описания монолитного приложения, так и микросервисной архитектуры;
  • Фокусироваться на описании архитектуры, абстрагировавшись от внешних систем.

Структура диаграммы

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

Приложения — отделимые приложения, которые описывают микросервисный подход.

Компоненты — основные строительные блоки приложения. Модули объединяют компоненты.

Внутренние связи между компонентами — обозначают связи между компонентами, а внешние связи — с другими системами или между микросервисами. Передаваемые объекты — обозначают связи между компонентами системы или вне.

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

Компоненты

Компоненты, это изолированный с точки зрения логики кусок кода, который может в реальности представлять собой класс или отдельный файл. Фактически, все, что вы можете выделить в виде класса с инкапсулированной логикой — это компонент.

Это может быть: контроллер, которые обрабатывает входящие запросы; сервис, отвечающий за бизнес логику работы с платежами; репозиторий, взаимодействующий с базой данных; обработчик event событий при использовании event sourcing; бизнес-entity пользователя, содержащие поля для него и методы работы. Для того чтобы максимально полно описать компонент можно указать следующие параметры:

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

Внутренние связи

Неразрывной стрелкой показываются связи между компонентами системы. При этом, направление стрелки указывает направление зависимости (вызова методов).

Если комплект UserContoller требует вызова метода из UserService
Если комплект UserContoller требует вызова метода из UserService

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

Внешние связи

Пунктирной стрелкой обозначится входящее или исходящее сообщение, или событие, обозначающие "в" или "из" внешней системой. Это может быть API вызовов, сообщения через шину RMQ в другие части системы, запрос в базу данных или интеграция с внешним API. В описании можно дать:

  • Название команды;
  • Тип запроса;
  • Название внешнего сервиса.
Пример обозначения внешних связей
Пример обозначения внешних связей

Модули

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

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

Модули имеют названия и группируют внутри себя компоненты, отображая свои границы
Модули имеют названия и группируют внутри себя компоненты, отображая свои границы

Модульность может меняться от одного архитектурного подхода к другому. Например, для Nest.js или Angular уже есть такое понятие как модуль, а для React модулем может выступать папка, в которой сгруппированы компоненты. Для С# это может быть Namespace или логически выделенный кусок приложения.

Приложения

Если система, которую вы хотите описать, состоит не из одного приложения, а из нескольких, можно использовать обертку приложения, которое объединяет в себя модули. Пунктирными стрелками отмечаются связи между ними так, как если бы они были внешним системами. Аналогично можно добавить описание и протокол взаимодействия.

Пример обозначения приложений
Пример обозначения приложений

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

Передаваемые объекты

При передаче данных между компонентами системы, может возникнуть необходимость описать их структуру. Обычно такие объекты носят название DTO (data transfer object). Они обозначаются прямоугольниками с закруглёнными на 50% углами. Можно добавить не только название DTO, но и его тип: event, query, command.

Пример обозначения передаваемых объектов
Пример обозначения передаваемых объектов

Детализация

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

Пример детализации
Пример детализации

Пример

Давайте возьмём для примера упрощенный клон MailChimp, который позволяет формировать списки пользователей для рассылки и отправлять им письма. В реальности описать большую систему таким образом будет проблематично. Поэтому я рекомендую использовать диаграммы для обсуждения конкретного решения проблемы или первоначальной архитектуры. Но даже на этом примере можно проследить использование всех компонентов.

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

Вот так выглядит готовая схема приложения:

-8

Она специально сделана детально, чтобы показать все возможности. Мы описали все возможные роуты, структуры баз, логику разбивки на модули. Отдельно выделил сложную сагу, которая призвана управлять логикой отправки кампании (можно было реализовать и по иному, в данном случае - это пример одной из возможных реализаций).

Заключение

Я описал мое видение нотации описания архитектуры приложения, с учётом опыта использования в команде. На практике решение позволило в кратчайшие сроки обсуждать изменения в архитектуре и планировать полноценные сервисы и приложения.

Вы можете использовать эту нотацию в любом удобном для вас инструменте, например draw.io или visio. Для удобства я подготовилъ готовую библиотеку в Figma, которая позволит быстро рисовать диаграммы, добавляя компоненты из библиотеки. Вы можете скачать её тут.

Бесплатные полезности

1. Смотрите видео: код-ревью, собеседования и новости разработки на нашем Дзене – https://dzen.ru/purpleschool?tab=longs

2. Создайте личный план обучения и получите доступ к базе из 500+ бесплатных уроков в бесплатных картах развития на нашем сайте – https://purpleschool.ru/skills

3. Разберитесь в том, как устроен мир IT на бесплатном курсе «Основы разработки» – https://purpleschool.ru/course/code-basics