Урок 04.04: Sequence Diagram (Диаграмма последовательности)
Цель урока
Научиться проектировать и документировать взаимодействие между компонентами системы с помощью Sequence Diagram. После этого урока вы сможете:
- Строить диаграммы последовательности для любых сценариев (от простого запроса к БД до распределённой Saga)
- Понимать, когда и почему Sequence Diagram — главный инструмент аналитика при интеграции
- Использовать комбинированные фрагменты (alt, opt, loop, par, break, critical, ref)
- Проектировать асинхронные взаимодействия через очереди сообщений
- Писать сложные PlantUML-диаграммы для процессов с ветвлениями, параллелизмом и обработкой ошибок
1. Что такое Sequence Diagram?
Sequence Diagram (диаграмма последовательности) — это UML-диаграмма, которая показывает взаимодействие объектов во времени. Время идёт сверху вниз, каждая стрелка — это сообщение, каждый прямоугольник — активация объекта.
1.1. Аналогия
Sequence Diagram — это сценарий пьесы:
Акт 1: Пользователь нажимает «Оплатить»
Акт 2: Фронтенд отправляет POST /api/payments
Акт 3: Бэкенд проверяет баланс
Акт 4: Бэкенд вызывает платёжный шлюз
...
Каждая стрелка — реплика персонажа. Время течёт от поднятия занавеса (начало сценария) до финальных аплодисментов (конец).
1.2. Место Sequence Diagram среди других диаграмм UML
| Диаграмма | Показывает | Когда использовать |
|---|---|---|
| Use Case | Кто что делает в системе | Начало: определить границы и функциональность |
| Activity | Поток работ, ветвления, роли | Описать бизнес-процесс или алгоритм |
| Sequence | Взаимодействие объектов во времени | Спроектировать интеграцию, API, сценарий |
| Class | Сущности, атрибуты, связи | Спроектировать доменную модель |
| State Machine | Состояния объекта и переходы | Описать жизненный цикл (заказ: новый → оплачен → отгружен) |
Sequence Diagram — мост между архитектурой и кодом. Если Use Case отвечает на вопрос «ЧТО?», то Sequence Diagram — на вопрос «КАК именно?».
2. Почему Sequence Diagram — главный инструмент аналитика при проектировании интеграций?
2.1. Интеграция — это всегда последовательность вызовов
Любая интеграция — это протокол. Протокол — это набор правил: кто, кому, что, когда и в каком порядке говорит. Sequence Diagram — идеальный способ визуализировать этот протокол.
Пример: интеграция фронтенда и бэкенда — это не просто «фронтенд зовёт бэкенд». Это:
- Фронтенд отправляет POST /api/v1/orders с телом запроса
- Бэкенд проверяет авторизацию (JWT-токен в заголовке)
- Бэкенд валидирует тело запроса
- Бэкенд проверяет доступность товара на складе
- Бэкенд бронирует товар (запрос к Inventory Service)
- Бэкенд создаёт заказ в БД
- Бэкенд отправляет событие
order.createdв Kafka - Бэкенд возвращает 201 Created с ID заказа
- Фронтенд показывает результат пользователю
Без Sequence Diagram разработчик фронтенда и разработчик бэкенда могут по-разному понять последовательность. Фронтенд может ждать ответ до тайм-аута, а бэкенд — требовать повторного вызова.
2.2. Что даёт Sequence Diagram при проектировании интеграций
| Аспект | Без Sequence Diagram | С Sequence Diagram |
|---|---|---|
| Порядок вызовов | В голове аналитика, додумывается разработчиком | Визуально зафиксирован сверху вниз |
| Формат ответа | Может быть не определён | Каждый возврат — стрелка с типом ответа и статус-кодом |
| Альтернативные сценарии | Обнаруживаются на этапе разработки или тестирования | Закладываются в alt / opt / break фрагменты |
| Тайм-ауты | Сюрприз production | Видны как opt / break с условием тайм-аута |
| Синхронность/асинхронность | Путаница | Тип стрелки (→ vs ->>) однозначен |
| Количество API-методов | Оценка «на глаз» | Каждая вертикальная линия — потенциальный эндпоинт |
2.3. Типичный сценарий: фронтенд + бэкенд
При проектировании новой фичи аналитик делает:
Use Case ──► Sequence Diagram (frontend → backend) ──► OpenAPI spec
│
└──► Тест-кейсы (QA)
Sequence Diagram — это контракт между фронтендом и бэкендом:
Фронтенд говорит:
«Я отправляю POST на /orders с телом {items, total}»
«Я ожидаю 201 с {orderId, status: "CREATED"}»
«На 422 я показываю ошибку валидации»
Бэкенд говорит:
«Да, я принимаю POST на /orders»
«Сначала проверяю JWT, потом валидирую, потом создаю заказ»
«Вот какие ошибки я могу вернуть: 400, 401, 422, 409, 500»
Без Sequence Diagram этот диалог идёт устно или в чате — и неизбежно возникают расхождения.
2.4. Sequence Diagram в Lifecycle проекта
| Фаза проекта | Как Sequence Diagram помогает |
|---|---|
| Discovery / Анализ | Уточнить сценарий с заказчиком: «Так вы представляете этот процесс?» |
| Архитектура | Согласовать интеграцию между командами (кто что вызывает) |
| Разработка | ТЗ для разработчика: порядок вызовов, типы ответов, обработка ошибок |
| Тестирование | Карта тест-кейсов: каждый alt/opt/break → отдельный тест |
| Документирование | Визуальная документация API для новых членов команды |
3. Ключевые элементы Sequence Diagram
3.1. Линии жизни (Lifelines)
Lifeline — это пунктирная вертикальная линия, которая показывает существование объекта во времени. Сверху — прямоугольник с именем объекта.
┌──────────────┐
│ Service │
├──────────────┤
│ Экземпляр │
└──────────────┘
│
│ (пунктир — время идёт вниз)
│
▼
Типы участников (lifelines):
| Тип | Нотация PlantUML | Когда использовать |
|---|---|---|
| Actor (внешний пользователь) | actor "Имя" |
Человек или внешняя система, инициирующая сценарий |
| Participant (участник) | participant "Имя" |
Любой компонент системы (по умолчанию) |
| Database (БД) | database "Имя" |
База данных, хранилище |
| Entity (сущность) | entity "Имя" |
Доменная сущность |
| Control (контроллер) | control "Имя" |
Управляющий компонент (Controller, Service) |
| Boundary (граница) | boundary "Имя" |
Граничный объект (UI, API Gateway) |
| Collections (очередь) | collections "Имя" |
Очередь сообщений (Kafka, RabbitMQ) |
Правила для Lifeline:
- Каждой Lifeline давайте осмысленное имя — не «Service 1», а
Inventory ServiceилиUser Service - Если Lifeline представляет конкретный экземпляр — используйте нотацию
имя:Тип, напримерstorage:PostgreSQL - Lifeline может быть уничтожена (крестик внизу) — если объект временный
3.2. Фокус управления (Activation Bar / Execution Specification)
Activation Bar (или Execution Specification) — узкий прямоугольник на Lifeline. Показывает, когда объект активен — выполняет операцию, ждёт ответа от другого объекта или обрабатывает данные.
│
┌────┴────┐ ← Activation Bar начался (объект получил сообщение)
│ │
│ Active │
│ │
└────┬────┘ ← Activation Bar закончился (объект вернул ответ)
│
Правила Activation Bar:
- Начало: объект получает сообщение (стрелка входит в Lifeline)
- Конец: объект возвращает ответ (пунктирная стрелка) или завершает выполнение
- Вложенность: если объект вызывает другой объект, Activation Bar продолжается до возврата
- Один бар: у объекта обычно один Activation Bar (UML допускает несколько вложенных, но на практике это редкость)
Пример — вложенность активаций:
Frontend Backend Database
│ │ │
│── HTTP ──────►│ │ ← Activation Bar у Backend начался
│ │── SQL ───────►│ ← Activation Bar у DB начался
│ │◄── rows ─────│ ← Activation Bar у DB закончился
│◄── HTTP 200 ──│ │ ← Activation Bar у Backend закончился
│ │ │
Зачем нужны Activation Bar?
- Показывают, кто сколько времени занят
- Помогают найти узкие места (один объект долго активен — возможно, нужен асинхронный вызов)
- Делают диаграмму читаемой: видно, кто выполняет работу последовательно, а кто параллельно
3.3. Сообщения (Messages)
Типы сообщений:
| Тип | PlantUML | Визуал | Смысл | Пример |
|---|---|---|---|---|
| Синхронное | A -> B: запрос |
Сплошная стрелка с залитым треугольником | A отправляет сообщение и ждёт ответ. Пока B не ответит, A не продолжает. | HTTP-запрос: POST /api/v1/orders |
| Асинхронное | A ->> B: событие |
Сплошная стрелка с открытой стрелкой | A отправляет сообщение и не ждёт ответа, продолжает работу. | Отправка в Kafka: order.created |
| Возврат (Reply) | B --> A: ответ |
Пунктирная стрелка | B возвращает результат A. Всегда после синхронного вызова. | HTTP 200 OK, 201 Created, 409 Conflict |
| Self-вызов | A -> A: метод() |
Стрелка в себя | A вызывает свой внутренний метод. | this.validateOrder(), this.calculateTotal() |
| Create | create B \n A -> B: new() |
Сплошная стрелка с созданным объектом | A создаёт новый объект B. | Создание сессии, создание DTO |
| Destroy | destroy C |
Крестик внизу | A уничтожает объект C. | Закрытие соединения, удаление временного файла |
Синхронное vs Асинхронное — ключевое различие
Синхронное сообщение:
Клиент Сервер
│ │
├────── GET /api ────────►│
│ │
│ (клиент ждёт) │ ← Клиент заблокирован
│ │
│◄───── HTTP 200 ─────────│
│ │
│ (клиент продолжает) │
- Поток выполнения блокируется до получения ответа
- Гарантия: сообщение доставлено (ответ получен)
- Риск: тайм-аут (сервер не ответил за N секунд)
Асинхронное сообщение:
Producer Kafka Consumer
│ │ │
├───── send(event) ───►│ │
│ не ждёт │ │
│ (продолжает работу) ├───── receive ──────►│
│ │ │
- Поток выполнения не блокируется
- Гарантия: доставка не гарантирована (нужны настройки Kafka: acks=all)
- Примеры: отправка email, логирование, обновление аналитики
Как выбирать:
Синхронно, если:
• Клиенту нужен результат сейчас
• Нужна гарантия доставки
• Операция быстрая (< 1 сек)
• Команда: POST / PUT / PATCH / DELETE (часто)
Асинхронно, если:
• Клиенту не нужен результат немедленно
• Операция долгая (генерация отчёта, конвертация видео)
• Это уведомление (email, push, SMS)
• Высокая нагрузка — нужна буферизация
3.4. Возвратные сообщения (Reply Messages)
Правила возврата:
- Каждое синхронное сообщение может иметь возврат (но не обязан — вызов метода void)
- Возврат — пунктирная стрелка
-->(PlantUML:B --> A: результат) - Возврат завершает Activation Bar у получателя
- На возврате можно указать:
- HTTP-статус-код (
201 Created,409 Conflict) - Тип возвращаемых данных (
OrderDTO,List<Product>) - Идентификатор созданной сущности (
orderId: 12345)
- HTTP-статус-код (
Важно: возвраты не должны плодиться. Если у вас 10 синхронных вызовов и 10 возвратов — это нормально. Но не рисуйте возвраты в асинхронных сообщениях — это противоречие (асинхронный вызов по определению не ждёт ответа).
4. Комбинированные фрагменты (Combined Fragments)
Combined Fragment — это прямоугольный блок с оператором в левом верхнем углу, который определяет условия выполнения внутри блока.
4.1. Полный список операторов
| Оператор | Название | Когда использовать |
|---|---|---|
| alt | Alternative (альтернатива) | Если-иначе: несколько взаимоисключающих потоков |
| opt | Optional (опция) | Блок выполняется только при условии |
| loop | Loop (цикл) | Повторный запрос (пагинация, retry) |
| par | Parallel (параллельно) | Параллельные независимые действия |
| break | Break (прерывание) | Прерывание сценария при ошибке |
| critical | Critical (критический) | Атомарная секция (транзакция) |
| ref | Reference (ссылка) | Ссылка на другую диаграмму |
| neg | Negative (негативный) | То, что НЕ должно произойти (запрещённая последовательность) |
| strict | Strict (строгий) | Строгий порядок сообщений внутри |
| seq | Sequential (последовательный) | Слабая последовательность (по умолчанию) |
| ignore | Ignore (игнорировать) | Важные, но не показанные сообщения |
| consider | Consider (учитывать) | Какие сообщения показаны |
4.2. alt — Альтернатива (if-else, switch-case)
Синтаксис PlantUML:
alt условие_1
A -> B: сообщение 1
else условие_2
A -> B: сообщение 2
else
A -> B: сообщение 3 (else по умолчанию)
end
Пример — обработка платежа:
alt [balance >= total]
Frontend -> Backend: POST /payments {amount, orderId}
Backend -> PaymentGateway: charge(amount, token)
PaymentGateway --> Backend: success
Backend --> Frontend: 201 {paymentId, status: "completed"}
Frontend -> User: Показать "Оплата прошла успешно"
else [balance < total]
Backend --> Frontend: 402 {error: "insufficient_funds"}
Frontend -> User: Показать "Недостаточно средств"
else [payment_gateway_unavailable]
Backend --> Frontend: 504 {error: "gateway_timeout"}
Frontend -> User: Показать "Платёжная система временно недоступна"
end
Правила alt:
- ровно одна ветка выполняется (взаимоисключение)
- минимум две ветки (иначе —
opt) - можно использовать
elseдля «ни одно из условий» (как default в switch)
4.3. opt — Опция (необязательный блок)
Отличие от alt: opt — это alt с одной веткой. Выполняется, если условие истинно. Если ложно — блок пропускается.
Синтаксис PlantUML:
opt условие
A -> B: сообщение
end
Пример — купон на скидку:
opt [couponCode != null]
Frontend -> Backend: GET /api/v1/coupons/{code}
Backend --> Frontend: 200 {discount: 15%}
Frontend -> User: Показать "Применён купон: скидка 15%"
end
Когда opt, а когда alt?
| Ситуация | Что использовать |
|---|---|
| Блок выполняется или нет | opt |
| Есть два взаимоисключающих варианта | alt (ветка else пустая — некрасиво, лучше opt) |
| Есть default-ветка (ничего не делать) | opt |
| Три и более варианта | alt с несколькими else |
4.4. loop — Цикл (повторение)
Синтаксис PlantUML:
loop N раз / while условие
A -> B: сообщение
end
Три варианта записи:
loop 3 раза
A -> B: попытка запроса
end
loop while (page.hasNext())
A -> B: GET /items?page={page}
B --> A: [ItemDTO]
end
loop until (response.status == 200)
A -> B: POST /api/v1/retry
end
Пример — Retry Pattern (повтор при ошибке):
loop 3 раза
Frontend -> Backend: POST /api/v1/payments
alt [status == 200]
break
else [status == 503]
' Продолжить цикл
end
end
Правила loop:
- Всегда есть условие выхода (иначе — бесконечный цикл)
- На диаграмме должно быть понятно, когда цикл завершается
- Для retry используйте
loop + breakпри успехе
4.5. par — Параллельные действия
Синтаксис PlantUML:
par
A -> B: действие 1
else
A -> C: действие 2
else
B -> D: действие 3
end
Пример — параллельные уведомления:
par
Backend -> EmailService: отправка email с подтверждением
else
Backend -> PushService: отправка push-уведомления
else
Backend -> Analytics: логирование события "Заказ создан"
end
Важно: par НЕ означает гонку. Все ветки выполняются (UML не гарантирует порядок внутри par). Если нужно синхронизировать — используйте critical.
4.6. break — Прерывание сценария
Синтаксис PlantUML:
break условие
A -> B: аварийное завершение
end
Пример — авторизация не пройдена:
Frontend -> Backend: GET /api/v1/orders
Backend -> AuthService: validateToken(token)
alt [token invalid]
AuthService --> Backend: invalid
Backend --> Frontend: HTTP 401 Unauthorized
break
else [token valid]
AuthService --> Backend: valid
end
' Сюда попадаем только если break не сработал
Backend -> Database: SELECT * FROM orders
Когда break vs alt для ошибки?
| Аспект | alt |
break |
|---|---|---|
| Поток продолжается после | Да (ветка else) | Нет (сценарий завершён) |
| Подходит для | Вариантов одного сценария | Раннего завершения при ошибке |
| Визуально | Зелёный vs Красный (субъективно) | «Точка невозврата» |
4.7. ref — Ссылка на другую диаграмму
Синтаксис PlantUML:
ref over A, B : Авторизация пользователя
Назначение: дробление большой диаграммы на части.
Когда использовать ref:
- Диаграмма стала слишком большой (> 25 сообщений)
- Один и тот же подпроцесс используется в нескольких сценариях
- Вы хотите скрыть внутренние детали (например, «Звонок к Payment Gateway»)
Пример дробления:
' Главная диаграмма
Customer -> Frontend: Оформить заказ
Frontend -> Backend: POST /api/v1/orders
ref over Backend, PaymentGateway : Процесс оплаты (см. отдельную диаграмму)
Backend --> Frontend: 201 Created
Frontend --> Customer: Подтверждение заказа
5. Сложный пример: Процесс оплаты заказа через сторонний платежный шлюз
5.1. Постановка задачи
Спроектируем процесс оплаты заказа в интернет-магазине через внешний платёжный шлюз (например, Stripe / YooKassa / Tinkoff Acquiring).
Участники:
| Lifeline | Тип | Роль |
|---|---|---|
| Покупатель | Actor | Человек, совершающий покупку |
| Frontend | Participant | UI веб-приложения (SPA) |
| Backend (Order Service) | Participant | Серверная логика |
| Database (PostgreSQL) | Database | Хранилище заказов и транзакций |
| Payment Gateway | Participant | Внешняя платёжная система (Stripe) |
| Auth Service | Participant | Сервис авторизации (JWT) |
| Email Service | Participant | Сервис отправки уведомлений |
Требования к сценарию:
- Покупатель инициирует оплату из корзины
- Перед оплатой — проверка JWT-токена (авторизация)
- Backend резервирует товар на складе (Inventory Service — синхронно)
- Backend создаёт транзакцию в БД со статусом
PENDING - Backend отправляет запрос на списание средств в Payment Gateway
- Платёжный шлюз может ответить успехом, ошибкой или запросить 3D-Secure (дополнительная аутентификация)
- При успехе: заказ переводится в статус
PAID, отправляется событие в Email Service - Параллельно с уведомлением: аналитика логирует событие
- При неудаче: заказ остаётся в статусе
PENDING, покупателю показывается ошибка - При 3D-Secure: покупатель перенаправляется на страницу банка, после подтверждения — callback от шлюза
5.2. PlantUML-код
@startuml
skinparam backgroundColor #FEFEFE
skinparam participantPadding 20
title Процесс оплаты заказа через платежный шлюз
' ========== Участники ==========
actor "Покупатель" as customer
participant "Frontend (SPA)" as frontend
participant "Order Service" as backend order 10
database "PostgreSQL" as db order 20
participant "Auth Service" as auth order 5
participant "Inventory Service" as inventory order 15
participant "Payment Gateway\n(Stripe)" as gateway order 25
participant "Email Service" as email order 30
participant "Analytics Service" as analytics order 35
' ========== 1. Инициализация ==========
== Шаг 1: Авторизация и проверка корзины ==
customer -> frontend: Нажать «Оплатить заказ»
activate frontend
frontend -> frontend: Собрать данные корзины\nиз локального состояния
frontend -> auth: GET /api/v1/auth/validate (JWT token)
activate auth
alt [token невалиден / истёк]
auth --> frontend: HTTP 401 Unauthorized
deactivate auth
frontend -> customer: Показать «Сессия истекла, войдите заново»
stop
else [token валиден]
auth --> frontend: HTTP 200 {userId, role, exp}
deactivate auth
end
' ========== 2. Резервирование ==========
== Шаг 2: Проверка и резервирование товара ==
frontend -> backend: POST /api/v1/orders/init {items, total, currency}
activate backend
backend -> auth: validateToken(token)
activate auth
auth --> backend: {userId, role}
deactivate auth
backend -> db: BEGIN TRANSACTION
activate db
backend -> db: SELECT items, stock FROM inventory\nWHERE item_id IN (...) FOR UPDATE
db --> backend: [{itemId, stock}]
alt [по какому-то товару недостаточно остатка]
backend -> db: ROLLBACK
deactivate db
backend --> frontend: HTTP 409 {error: "item_out_of_stock", itemId}
deactivate backend
frontend -> customer: Показать «Товар X закончился»
stop
else [все товары в наличии]
backend -> db: UPDATE inventory SET stock = stock - 1\nWHERE item_id IN (...)
db --> backend: rows updated
end
backend -> db: INSERT INTO orders (user_id, status, total, currency)\nVALUES (?, 'RESERVED', ?, ?) RETURNING id
db --> backend: orderId = 12345
backend -> db: COMMIT
deactivate db
' ========== 3. Инициализация платежа ==========
== Шаг 3: Создание платежа в платёжном шлюзе ==
backend -> db: INSERT INTO payments (order_id, amount, currency, status)\nVALUES (12345, ?, ?, 'PENDING')
activate db
db --> backend: paymentId = 54321
deactivate db
backend -> gateway: POST /v1/charges {amount, currency, return_url, metadata}
activate gateway
note right of gateway: Платёжный шлюз может\nзапросить 3D-Secure\n(доп. аутентификация)
alt [платёж выполнен сразу — без 3DS]
gateway --> backend: 200 {id: "ch_12345", status: "succeeded"}
deactivate gateway
note left: Стандартный платёж\nбез дополнительной верификации
else [требуется 3D-Secure]
gateway --> backend: 200 {id: "ch_12345", status: "requires_action",\nnext_action: {type: "redirect_to_url", url: "https://..."}}
deactivate gateway
' 3D-Secure: перенаправление на страницу банка
backend --> frontend: HTTP 200 {action: "redirect", url: "https://...", paymentId: 54321}
deactivate backend
frontend -> customer: Перенаправить на страницу 3D-Secure банка
customer -> frontend: Пройти верификацию (код из SMS/приложения банка)
activate frontend
' Callback от шлюза после 3DS
frontend -> backend: POST /api/v1/payments/confirm {paymentIntentId: "pi_12345"}
activate backend
backend -> gateway: GET /v1/charges/ch_12345
activate gateway
alt [3DS пройден — платёж подтверждён]
gateway --> backend: 200 {status: "succeeded"}
deactivate gateway
else [3DS не пройден]
gateway --> backend: 200 {status: "requires_payment_method"}
deactivate gateway
backend --> frontend: HTTP 402 {error: "3ds_failed"}
deactivate backend
frontend -> customer: Показать «Ошибка верификации,\nпопробуйте другой способ оплаты»
stop
end
end
' ========== 4. Финализация заказа ==========
== Шаг 4: Финализация заказа и уведомления ==
backend -> db: BEGIN TRANSACTION
activate db
backend -> db: UPDATE orders SET status = 'PAID',\npaid_at = NOW() WHERE id = 12345
db --> backend: OK
backend -> db: UPDATE payments SET status = 'SUCCEEDED'\nWHERE id = 54321
db --> backend: OK
backend -> db: COMMIT
deactivate db
' Параллельные уведомления
par
' Ветка 1: Отправка email
backend -> email: sendPaymentConfirmation(orderId=12345, email=user@example.com)
activate email
note right: Асинхронная отправка\n(через очередь)
email --> backend: accepted (202)
deactivate email
else
' Ветка 2: Логирование в аналитику
backend -> analytics: logEvent("order.paid", {orderId: 12345, total, currency})
activate analytics
analytics --> backend: logged
deactivate analytics
else
' Ветка 3: Снятие резерва (не обязательно в данном сценарии)
' Резерв уже снят на шаге 2 — это просто для демонстрации
end
' ========== 5. Ответ клиенту ==========
backend --> frontend: HTTP 201 {orderId: 12345, status: "paid", paymentId: 54321}
deactivate backend
frontend -> customer: Показать страницу «Заказ оплачен»\nс деталями и номером заказа
deactivate frontend
@enduml
5.3. Разбор диаграммы
Что демонстрирует этот пример:
| Элемент | Как используется |
|---|---|
| alt (3 шт.) | Валидация JWT, проверка остатков, 3D-Secure (успех/ошибка/фолбек) |
| par (1 шт.) | Параллельная отправка email + аналитика |
| stop (3 шт.) | Прерывание сценария при разных ошибках (401, 409, 402) |
| Activation Bar | У каждого участника при получении/обработке запроса |
| Синхронные вызовы | Все HTTP-запросы (фронтенд → бэкенд, бэкенд → шлюз) |
| Асинхронные вызовы | Email Service (backlog — принял запрос, но не гарантирует моментальную отправку) |
| Self-вызов | frontend -> frontend: Собрать данные корзины — внутренняя операция |
| Database transaction | BEGIN / COMMIT / ROLLBACK — явно показаны |
| Guard conditions | [token валиден], [все товары в наличии] — в квадратных скобках |
5.4. Что мы обнаружили в процессе построения
Анализируя процесс оплаты, мы выявили скрытые требования:
- Что делать с товаром, если 3D-Secure не пройден? → Оставить резерв или снять? Решение: снимать резерв через 30 минут (фоновый job) — это станет отдельным сценарием.
- Что делать с товаром, если платёж завис? → Добавить Compensating Transaction (отмена резерва).
- Нужен ли ретрай при ошибке шлюза? → Да,
loop 3с экспоненциальной задержкой. - Кто отвечает за тайм-аут? → Фронтенд ждёт 30 секунд, потом показывает «Сервис временно недоступен».
Без Sequence Diagram эти вопросы были бы обнаружены на этапе разработки или тестирования, с переделками и потерянным временем.
6. Паттерны Sequence Diagram для интеграций
6.1. Паттерн «Трёхзвенка» (3-Tier)
Стандартный паттерн для веб-приложений:
Actor → Frontend (UI) ↔ Backend (API) ↔ Database
Особенности:
- Frontend отправляет HTTP (синхронно)
- Backend обрабатывает бизнес-логику
- Database — хранилище
- Все вызовы синхронные
Когда использовать: стандартные CRUD-операции, простые бизнес-процессы.
6.2. Паттерн «Посредник» (Mediator / API Gateway)
Actor → API Gateway → Service A
↓
Service B
↓
Service C
Особенности:
- API Gateway — единая точка входа
- Gateway может агрегировать ответы от нескольких сервисов
- Gateway — «тонкий» (только маршрутизация) или «толстый» (агрегация, трансформация)
Когда использовать: микросервисная архитектура, когда клиенту нужно собрать данные из нескольких источников.
6.3. Паттерн «Сага (Хореография)» — распределённая транзакция
Service A → Service B → (успех) → Service C → (успех) → Done
↓ ↓
(ошибка) (ошибка)
↓ ↓
Service B Service B
компенсация компенсация
↓ ↓
Service A Service A
компенсация компенсация
Когда использовать: распределённые транзакции в микросервисах (заказ + оплата + доставка).
6.4. Паттерн «Асинхронная очередь» (Event-Driven)
Producer → Message Queue (Kafka / RabbitMQ) → Consumer
Особенности:
- Producer не ждёт ответа (асинхронный вызов)
- Consumer может быть не готов (сообщение в очереди)
- Надёжность: Kafka хранит сообщения на диске
Когда использовать: высокая нагрузка, слабая связность сервисов, уведомления.
6.5. Паттерн «Проверка перед действием» (Validate-Execute)
Actor → Backend: POST /action
Backend → Validation: check()
Validation → Backend: valid/invalid
alt [invalid]
Backend → Actor: 400 Bad Request
else [valid]
Backend → Database: INSERT ...
Backend → Actor: 201 Created
end
Когда использовать: когда валидация сложная и должна выполняться на сервере (не на фронтенде).
7. Sequence Diagram и тест-кейсы
Каждый путь на Sequence Diagram — это тест-кейс.
7.1. Карта тест-кейсов из диаграммы оплаты
| # | Путь на диаграмме | Условие | Ожидаемый результат | Тест-кейс |
|---|---|---|---|---|
| 1 | Happy Path | JWT валиден, товары в наличии, платёж без 3DS | 201 Created, заказ PAID | TC-01: Успешная оплата |
| 2 | JWT невалиден | Token expired / invalid | 401 Unauthorized, оплата не начинается | TC-02: Истекшая сессия |
| 3 | Товара нет в наличии | Stock = 0 для одного из товаров | 409 Conflict, заказ не создан | TC-03: Нет на складе |
| 4 | Платёж с 3DS успешно | 3DS пройден | 201 Created, заказ PAID | TC-04: 3DS успешно |
| 5 | Платёж с 3DS не пройден | 3DS failed | 402 Error, заказ RESERVED | TC-05: 3DS не пройден |
| 6 | Ошибка платёжного шлюза | Gateway timeout / 500 | Backend retry + 504 клиенту | TC-06: Шлюз недоступен |
| 7 | Email упал | Email Service 500 | Заказ PAID, уведомление не отправлено | TC-07: Fallback уведомления |
Правило: каждый alt и opt фрагмент добавляет минимум 1 тест-кейс. Каждый break — минимум 1 негативный тест.
7.2. Как аналитик строит тест-кейсы из Sequence Diagram
Sequence Diagram → выписать все alt/opt/break → для каждой ветки:
1. Какое сообщение-триггер?
2. Какое условие?
3. Какие сообщения внутри ветки?
4. Какой конечный результат?
Результат: таблица из 4 колонок (Триггер → Условие → Действия → Результат), которая передаётся QA-инженеру.
8. Sequence Diagram в PlantUML — полный справочник
8.1. Объявление участников с порядком
actor "Покупатель" as customer order 1
participant "Frontend" as ui order 2
participant "Backend" as svc order 3
database "DB" as db order 4
collections "Kafka" as kafka order 5
order N — гарантирует позицию слева направо.
8.2. Активации
A -> B: запрос
activate B ' начать активацию
B --> A: ответ
deactivate B ' закончить активацию
8.3. Создание и уничтожение
create PaymentDTO
backend -> PaymentDTO: new(amount, currency)
...
destroy PaymentDTO
8.4. Automatic activation (сокращённый синтаксис)
autoactivate on
A -> B: запрос ' activate B автоматически
B -> C: вызов ' activate C автоматически
C --> B: ответ ' deactivate C
B --> A: ответ ' deactivate B
autoactivate off
Внимание: автоактивация удобна для простых диаграмм, но на сложных диаграммах лучше управлять activate/deactivate вручную — точнее контроль.
8.5. Оформление
' Разделители
=== Раздел 1: Авторизация ===
' Цвет участника
participant "Service" as svc #LightBlue
' Заметки
note right of A: текст заметки
note over A, B: заметка на несколько\nлиний жизни
note left: комментарий
' Отступ
||| Пауза |||
' Форматирование текста
note right: <b>Важно</b>\n<color:red>ошибка</color>
8.6. Несколько уточнений
- Вложенные активации (Nested Activation) — допустимы, но их следует избегать (сложно читать)
- Activation Bar у Actor — не ставится (актёр — внешняя сущность, мы не контролируем его время выполнения)
- Асинхронные вызовы не имеют возврата — если возврат есть, вызов должен быть синхронным
9. Типичные ошибки и как их избежать
Ошибка 1: Sequence Diagram вместо Activity Diagram
Симптом: на диаграмме 15 участников, 40 сообщений, но нет альтернативных сценариев.
Проблема: Sequence Diagram описывает один конкретный сценарий. Если вы пытаетесь показать все ветвления бизнес-процесса на одной Sequence Diagram — используйте Activity Diagram или BPMN.
Как исправить:
- Business logic ветвления → Activity Diagram
- API-вызовы внутри одного сценария → Sequence Diagram
Ошибка 2: Слишком много alt-фрагментов
Симптом: диаграмма состоит на 60% из alt-фрагментов, вложенных друг в друга.
Проблема: Каждый alt — это отдельный тест-кейс. Три вложенных alt — это 8 (2³) комбинаций, которые невозможно протестировать.
Как исправить: Разбить на несколько диаграмм по одному alt на диаграмму. Или перейти на Activity Diagram.
Ошибка 3: Асинхронный вызов с возвратом
Симптом: A ->> B: запрос и B --> A: ответ.
Проблема: Если вызов асинхронный, A не ждёт ответа. Показывать возврат — противоречие.
Как исправить: Либо стрелка -> (синхронно, с ожиданием ответа), либо ->> без возврата (асинхронно, ответ не ожидается). Если асинхронному вызову всё же нужен ответ — используйте callback: второй асинхронный вызов от B к A, когда результат готов.
Ошибка 4: Нет обработки ошибок (только Happy Path)
Симптом: диаграмма показывает только успешный сценарий. Нет alt/break/opt для ошибок.
Проблема: Разработчик реализует только Happy Path, QA не проверяет ошибки, production падает.
Как исправить: Для каждого вызова добавьте alt [success] / [error]. Если ошибок много — хотя бы одну «общую» ветку error.
Ошибка 5: Lifeline не соответствует уровню абстракции
Симптом: На одной диаграмме Пользователь, HTTP-запрос, SQL-запрос, Сервер, Класс UserRepository.
Проблема: Смешение бизнес-уровня и технического уровня.
Как исправить: Выберите один уровень:
- Бизнес-уровень: Актёр → Система A → Система B
- Логический уровень: Frontend → API → Service → Database
- Технический уровень: Конкретные классы, методы, SQL-запросы
Не смешивайте их на одной диаграмме.
Ошибка 6: Отсутствие Activation Bar
Симптом: Lifelines есть, стрелки есть, но Activation Bar нет.
Проблема: Непонятно, кто в какой момент времени активен. Диаграмма выглядит как «рыба» без структуры.
Как исправить: Каждый синхронный вызов → activate у получателя, deactivate после ответа. Для асинхронных — активация при получении, деактивация после обработки.
Ошибка 7: Пересекающиеся стрелки
Симптом: стрелки от разных участников пересекаются, невозможно понять, к кому идёт сообщение.
Как исправить: Следите за порядком Lifeline. Группируйте участников: слева — инициатор, справа — внешние сервисы. Используйте order N в PlantUML.
10. Чек-лист: готовая Sequence Diagram
| № | Критерий | Как проверить |
|---|---|---|
| 1 | Название сценария указано | В заголовке диаграммы |
| 2 | Участники (Lifeline) определены | Каждый нужный компонент присутствует |
| 3 | Первое сообщение — от внешнего актёра | Инициация сценария |
| 4 | Каждое синхронное сообщение → стрелка с заполненным треугольником | A -> B |
| 5 | Каждое асинхронное → стрелка с открытым наконечником | A ->> B |
| 6 | У каждого синхронного вызова есть возврат | B --> A |
| 7 | Activation Bar есть у всех участников | activate / deactivate |
| 8 | Activation Bar не пересекается (у одного участника) | Нет двух одновременных активностей |
| 9 | Альтернативы покрыты (alt) | Есть ветки для ошибок |
| 10 | Опциональные шаги (opt) добавлены | Например, «отправить email» |
| 11 | Циклы (loop) не бесконечные | Есть условие выхода |
| 12 | Диаграмма не слишком велика | < 25 сообщений, иначе — ref |
| 13 | Уровень абстракции соблюдён | Не смешаны бизнес-уровень и технический |
| 14 | Все статус-коды HTTP явно указаны | 201, 401, 409, 402 |
| 15 | Асинхронные вызовы имеют очередь (collections) если нужно | Kafka, RabbitMQ |
11. Вопросы для самопроверки
- Почему Sequence Diagram считают «главным инструментом аналитика при интеграциях»? Назовите 3 причины.
- Чем синхронный вызов отличается от асинхронного? Какой тип стрелки в PlantUML у каждого?
- Что такое Activation Bar? Почему он не может пересекаться сам с собой?
- Какая разница между
altиopt? Приведите жизненный пример для каждого. - Что такое
break? Когда его использовать вместоalt? - Как на Sequence Diagram показать, что блок должен выполниться только при определённом условии?
- Как на Sequence Diagram показать параллельные действия?
- Как на Sequence Diagram показать, что сценарий прерывается при ошибке?
- Сколько тест-кейсов можно выделить из Sequence Diagram оплаты (пример из урока)? Назовите хотя бы 5.
- Что такое паттерн «Сага»? Как его смоделировать в Sequence Diagram?
- Что произойдёт, если нарисовать
A ->> B: запроси потомB --> A: ответ? Почему это ошибка? - Какую информацию можно извлечь из Sequence Diagram для написания OpenAPI-спецификации?
12. Практическое задание
Кейс: Процесс отмены заказа в интернет-магазине
Описание сценария:
Пользователь хочет отменить заказ, который ещё не отправлен.
- Пользователь открывает страницу заказа в личном кабинете
- Пользователь нажимает «Отменить заказ»
- Frontend отправляет запрос на отмену:
POST /api/v1/orders/{id}/cancel - Backend проверяет статус заказа в БД
- Если статус заказа —
PAIDилиRESERVED:- Backend вызывает платёжный шлюз для возврата денег (refund)
- Платёжный шлюз обрабатывает возврат (может завершиться успехом или ошибкой)
- Если refund успешен: Backend меняет статус заказа на
CANCELLED, возвращает товар на склад (Inventory Service) - Если refund не удался (например, превышен лимит на возвраты): Backend создаёт тикет для техподдержки, заказ остаётся в статусе
PAID
- Если статус заказа —
SHIPPEDилиDELIVERED:- Backend возвращает ошибку 400: «Заказ уже отправлен, отмена невозможна»
- Параллельно с отменой:
- Backend отправляет уведомление пользователю (email)
- Backend логирует событие в аналитику
- Frontend показывает результат пользователю (успех/ошибка/создан тикет)
Задание 1. Постройте Sequence Diagram
Создайте Sequence Diagram сценария отмены заказа.
Участники:
- Пользователь (actor)
- Frontend (participant)
- Order Service / Backend (participant)
- PostgreSQL (database)
- Payment Gateway (participant)
- Inventory Service (participant)
- Support System (participant) — для создания тикета
- Email Service (participant)
- Analytics Service (participant)
Требования:
- Минимум 2 фрагмента alt (проверка статуса, результат refund)
- Минимум 1 фрагмент par (уведомление + аналитика)
- Минимум 1 асинхронное сообщение (email)
- Явно показаны HTTP статус-коды на возвратах
- Транзакции в БД (BEGIN / COMMIT / ROLLBACK) — опционально, но приветствуется
- Activation Bar для каждого участника
Задание 2. PlantUML-код
Напишите полный PlantUML-код этой диаграммы. Убедитесь:
@startuml / @endumlс заголовком- Все участники объявлены с корректными типами
activate / deactivateдля каждого вызоваalt / else / else / endдля ветвленийpar / else / endдля параллельных действийstopдля завершения сценария- Код компилируется (проверьте на plantuml.com или в VS Code)
Задание 3. Карта тест-кейсов
На основе вашей Sequence Diagram составьте таблицу тест-кейсов:
| TC# | Сценарий | Условие | Входные данные | Ожидаемый результат |
|---|---|---|---|---|
| TC-01 | ... | ... | ... | ... |
Минимум 5 тест-кейсов.
Задание 4. Анализ ошибок
Даны 3 фрагмента Sequence Diagram. Найдите ошибки и объясните, почему это ошибка:
Фрагмент A:
actor User
participant Frontend
participant Backend
User -> Frontend: Нажать кнопку
Frontend -> Backend: POST /api/action
Backend -> Backend: process()
Backend --> Frontend: 200 OK
Frontend --> User: Результат
Фрагмент B:
actor User
participant ServiceA
participant ServiceB
User ->> ServiceA: Запрос
ServiceA ->> ServiceB: Асинхронный вызов
ServiceB --> ServiceA: Ответ
ServiceA --> User: Результат
Фрагмент C:
actor User
participant Frontend
participant Backend
participant DB
User -> Frontend: Действие
Frontend -> Backend: POST /api/orders
Backend -> DB: SELECT ... FOR UPDATE
DB --> Backend: rows
Frontend --> User: Результат
' Activation Bar не закрыт у Backend
Задание 5. Рефлексия
Напишите 3–5 предложений: «Почему Sequence Diagram — главный инструмент аналитика при проектировании интеграций фронтенда и бэкенда? Приведите один аргумент из своего опыта (или воображаемого опыта).»
13. Дополнительные материалы
- Книга: Martin Fowler — «UML Distilled», 3-е издание, глава 4 «Sequence Diagrams» (75 страниц, но ёмко)
- Спецификация: OMG UML 2.5.1, раздел 17 «Interactions» (формальное определение — 80+ страниц, для глубокого погружения)
- PlantUML: plantuml.com/sequence-diagram — официальная документация с примерами
- Видео: «UML Sequence Diagram Tutorial» на Lucidchart (15 минут, визуальное введение)
- Шпаргалка: «Sequence Diagram Cheat Sheet» — поищите в Google Images для одностраничной памятки
- Tool: draw.io (diagrams.net) — бесплатный редактор диаграмм, Sequence Diagram в разделе UML
- Tool: PlantUML VS Code Extension — для компиляции
.pumlфайлов внутри редактора - Паттерны: «Enterprise Integration Patterns» by Hohpe and Woolf — книга про интеграционные паттерны (Saga, Retry, Aggregator), которые отлично ложатся на Sequence Diagram
- Статья: Martin Fowler — «Design Stamina Hypothesis» — почему стоит тратить время на диаграммы перед кодом (проектная документация окупается на сложных сценариях)
Следующий урок: 04.05 — Class Diagram (Диаграмма классов)