Урок 04.03: Activity Diagram (Диаграмма деятельности)
Цель урока
Научиться моделировать бизнес-процессы, алгоритмы и потоки работ с помощью Activity Diagram. После этого урока вы сможете:
- Строить диаграммы деятельности с ветвлениями, параллельными потоками и дорожками
- Осознанно выбирать между Activity Diagram и BPMN под конкретную задачу
- Читать и писать Activity Diagram на PlantUML
- Применять продвинутые элементы (прерываемые регионы, обработчики исключений, сигналы)
- Валидировать диаграмму на логические ошибки
1. Что такое Activity Diagram?
Activity Diagram (диаграмма деятельности) — это UML-диаграмма для моделирования потоков управления и потоков данных. Она показывает последовательность действий, ветвления, параллельные процессы и зоны ответственности участников.
1.1. Аналогия для быстрого понимания
Представьте, что вы стоите на входе в аэропорт:
| Элемент Activity Diagram | Аналогия в аэропорту |
|---|---|
| Initial Node (●) | Вход в аэропорт |
| Action (⬭) | Прохождение паспортного контроля, сдача багажа |
| Decision (◇) | «Ваш рейс — внутренний или международный?» |
| Fork (▬) | Один пассажир садится в самолёт, багаж грузится отдельно — параллельно |
| Join (▬) | Пассажир и багаж встречаются в пункте назначения |
| Swimlane | Зона ответственности: Авиакомпания, Служба безопасности, Пассажир |
| Final Node (◉) | Выход из аэропорта по прибытии |
1.2. Где Activity Diagram в UML-семействе?
| Диаграмма | Тип | Показывает | Лучше всего для |
|---|---|---|---|
| Use Case | Поведенческая | Кто что делает в системе | Границы системы, функциональные требования |
| Activity | Поведенческая | Последовательность и параллелизм действий | Алгоритмы, бизнес-процессы, workflow |
| Sequence | Поведенческая | Обмен сообщениями во времени | Протоколы взаимодействия, сценарии |
| State Machine | Поведенческая | Жизненный цикл объекта | Статусы заказа, состояния документа |
| Class | Структурная | Сущности и их связи | Доменная модель, структура данных |
Все поведенческие диаграммы дополняют друг друга:
Use Case ──описывается с помощью──► Activity / Sequence
│
└──► каждый Use Case может быть детализирован Activity-диаграммой
Правило: один Use Case → как минимум один главный сценарий (happy path) — можно показать Activity Diagram. Если сценарий простой (3–5 шагов) — достаточно текстового описания. Если больше 5 шагов, есть ветвления и роли — нужна Activity Diagram.
2. Activity Diagram vs BPMN: когда что выбрать?
Это один из самых частых вопросов аналитика. Давайте разложим по полочкам.
2.1. Происхождение
- UML Activity Diagram — пришёл из мира разработки ПО. Изначально создавался для описания алгоритмов (как блок-схема «на стероидах»). Позже эволюционировал в сторону бизнес-процессов.
- BPMN — создавался для бизнес-процессов и их исполнения в BPM-движках (Camunda, ELMA, Bizagi).
2.2. Сравнительная таблица
| Критерий | UML Activity Diagram | BPMN |
|---|---|---|
| Стандарт | OMG UML 2.5+ | OMG BPMN 2.0+ |
| Год появления | 1997 (UML 1.0) | 2004 (BPMN 1.0) |
| Сложность нотации | Средняя (~20 элементов) | Высокая (~100+ элементов) |
| События | 3 типа (Start, Stop, Flow Final) | ~50 типов (Timer, Message, Error, Escalation, Signal, Compensation…) |
| Данные | Object Node, Data Store | Data Object, Data Store, Data Input/Output |
| Дорожки | Swimlane (одноуровневые) | Pool + Lane (двухуровневые, вертикальные/горизонтальные) |
| Исполняемость | Нет (только документирование) | Да (BPMN 2.0 — XML, исполняемый движками) |
| Читаемость для бизнеса | Средняя | Хорошая (при использовании базовых элементов) |
| Инструменты | Draw.io, PlantUML, Enterprise Architect, Lucidchart | Camunda Modeler, Bizagi, ARIS, ELMA |
| Основная аудитория | Разработчики + аналитики | Бизнес-аналитики + BPM-специалисты |
2.3. Алгоритм выбора
Задайте себе 3 вопроса:
Вопрос 1: Кто будет читать диаграмму?
Если чисто разработчики → Activity Diagram
Если бизнес-заказчики + разработчики → Activity Diagram (проще вход)
Если бизнес-заказчики будут её утверждать как регламент → BPMN
Вопрос 2: Будет ли процесс исполняться в BPM-движке?
Если да → только BPMN (Activity не исполняется)
Если нет → можно Activity (или BPMN — на ваш вкус)
Вопрос 3: Какова сложность процесса?
Простой алгоритм (< 10 действий, 1–2 роли) → Activity (быстрее и проще)
Сложный процесс с таймерами, ошибками, сообщениями, компенсациями → BPMN
Правило большого пальца: Если вы сомневаетесь — рисуйте Activity Diagram. Её всегда можно перевести в BPMN, если понадобится исполнение. Обратный перевод (BPMN → Activity) сложнее из-за потери событийной информации.
2.4. Когда Activity Diagram однозначно лучше BPMN
- Описание алгоритма (ветвления, циклы, параллельные вычисления)
- Техническая документация (как работает внутренний модуль системы)
- Проектная документация для разработчиков (Activity привычнее для IT)
- Быстрое прототипирование процесса на доске/в PlantUML
- Описание вариантов использования (Use Case) — один Use Case → одна Activity Diagram
2.5. Когда BPMN однозначно лучше Activity
- Процесс будет исполняться в Camunda / ELMA / другие BPM-движки
- Нужны сложные события (таймеры «ожидание 3 дня», сообщения между процессами, ошибки с компенсациями)
- Сложные взаимодействия между участниками (пулы с потоками сообщений)
- Требуется формальный регламент («Утверждаю» — подпись)
- Процесс содержит итеративный цикл ревью с возвратом на доработку
2.6. Шпаргалка по нотациям для аналитика
| Задача | Какая диаграмма лучше |
|---|---|
| Описать шаги регистрации пользователя | Activity |
| Смоделировать процесс согласования договора | BPMN (если будет в СЭД) / Activity (если в документации) |
| Показать алгоритм расчёта скидки | Activity |
| Описать процесс обработки претензии с таймерами | BPMN |
| Сделать AS-IS анализ текущего процесса | BPMN / Activity — на ваш вкус |
| Детализировать Use Case «Оплатить заказ» | Activity |
| Исполнить процесс в Camunda | BPMN — безальтернативно |
3. Ключевые элементы Activity Diagram
3.1. Полный справочник элементов
| Элемент | Нотация | Название | Описание |
|---|---|---|---|
| ● | Залитый круг | Initial Node (Узел начала) | Старт процесса. Обычно один на диаграмму. |
| ◉ | Круг в круге | Activity Final Node (Узел завершения) | Завершает все потоки процесса. |
| ⊗ | Круг с крестом | Flow Final Node (Узел завершения потока) | Завершает один поток, другие продолжаются. |
| ⬭ | Скруглённый прямоугольник | Action (Действие) | Атомарный шаг процесса. |
| ⬭ с волнистым краем | Скруглённый прямоугольник с волнистым верхом | Accept Event Action | Ожидание внешнего события (сообщение, таймер). |
| ⬭ с зубчатым краем | Скруглённый прямоугольник с зубцом | Send Signal Action | Отправка сигнала другому процессу. |
| ◇ | Ромб | Decision Node (Узел решения) | Ветвление: один вход, N выходов с условиями. |
| ◇ | Ромб | Merge Node (Узел слияния) | Сведение альтернативных путей. |
| ▬ | Утолщённая линия | Fork Node (Узел разветвления) | Один вход → N параллельных выходов. |
| ▬ | Утолщённая линия | Join Node (Узел синхронизации) | N входов → один выход (ждём все потоки). |
| Прямоугольная секция | Дорожка | Swimlane (Дорожка) | Зона ответственности роли/актёра. |
| Прямоугольник | Прямоугольник | Object Node (Узел объекта) | Данные, передаваемые между действиями. |
| Прямоугольник с «бумажкой» | Прямоугольник с загнутым углом | Data Store (Хранилище) | Постоянные данные (БД, файл). |
| Пунктирный прямоугольник с «молнией» | Пунктир с зигзагом | Interruptible Region | Область, которая может быть прервана. |
| Зигзаг у действия | Exception Handler | Обработчик ошибки действия. |
3.2. Decision Node — узел решения (ромб)
Назначение: выбор одного пути из нескольких на основе условия.
Правила:
- Ровно один входящий поток
- От 2 до N исходящих потоков
- На каждом исходящем потоке — условие в квадратных скобках
[условие] - Условия должны покрывать все возможные случаи (полнота). Если остался непокрытый случай — добавьте
[иначе]/[else]
Пример:
┌─ [сумма ≥ 1000] → Применить скидку 10%
Проверить ┤
сумму ├─ [500 ≤ сумма < 1000] → Применить скидку 5%
│
└─ [else] → Без скидки
Распространённая ошибка: ветвление на 2 исхода (True / False), но не предусмотрен случай, когда условие не определено (null). Всегда добавляйте [else].
3.3. Merge Node — узел слияния (тоже ромб)
Назначение: свести несколько альтернативных путей в один.
Важно: Merge не синхронизирует потоки. Он просто пропускает любой пришедший поток дальше. Если вы хотите дождаться всех потоков — используйте Join.
Правило: Merge не имеет собственного условия — он «прозрачен» для управления.
Когда нужен Merge:
- После Decision, когда несколько веток снова сходятся в общий поток
- Без Merge диаграмма становится «паутиной» из пересекающихся стрелок
3.4. Fork vs Decision — главное различие
Многие путают Fork и Decision. Запомните раз и навсегда:
| Характеристика | Decision (◇) | Fork (▬) |
|---|---|---|
| Сколько путей выбирается? | ОДИН (альтернатива) | ВСЕ (параллельно) |
| Условия на выходах | Есть (всегда) | Нет (никогда) |
| Аналогия в коде | if-else / switch |
async / threading |
| Пример | Если слот свободен → запись, иначе → ошибка | Параллельно: отправить email + создать задачу в CRM |
Проверочный вопрос: «Могут ли выполниться оба выхода одновременно?»
- Да → Fork
- Нет → Decision
3.5. Fork / Join — параллельные потоки
Fork Node (▬): разделяет один поток на несколько параллельных. Все выходы выполняются одновременно (или в произвольном порядке).
Join Node (▬): синхронизирует несколько параллельных потоков в один. Ждёт завершения всех входящих потоков.
Пример корректного использования:
┌─→ Отправить email клиенту ──┐
│ │
Fork ─┼─→ Списать товар с остатков ──┼─→ Join → Обновить статус заказа
│ │
└─→ Отправить заказ на склад ──┘
Fork не может соединяться с Merge: если вам нужно разветвить на параллельные потоки, а потом свести их — используйте Fork + Join. Merge для этой цели не подходит (он не ждёт).
3.6. Initial Node / Final Node / Flow Final
Initial Node (●):
- Обозначает начало процесса
- Обычно один на диаграмму (UML допускает несколько, но на практике — один)
- Не имеет входящих стрелок, имеет одну исходящую
Activity Final Node (◉ — круг в круге):
- Завершает все потоки процесса
- Если один поток дошёл до ◉ — все остальные потоки тоже прекращаются
- На диаграмме может быть один или несколько (но если один сработал — остальные не важны)
Flow Final Node (⊗ — круг с крестом):
- Завершает только один поток, не влияя на другие
- Используется внутри Fork/Join, когда одна из параллельных веток может завершиться раньше других
Сравнение Final Node:
Пример с Fork:
Fork ─┬─→ Действие A ──→ ⊗ (завершилось A, B продолжается)
└─→ Действие B ──→ ◉ (B завершило ВЕСЬ процесс)
Flow Final (⊗) завершил ветку A, но процесс продолжился в B. А вот B дошёл до Activity Final (◉) — и всё остановилось.
3.7. Swimlane — дорожки
Назначение: визуально разделить действия по зонам ответственности.
Как работают:
- Каждая дорожка подписана именем роли / актёра / системы
- Все действия внутри дорожки выполняются этим участником
- Границы дорожек — сплошные линии
- Потоки управления могут пересекать границы дорожек (это нормально)
Сколько дорожек нужно?
| Количество ролей | Нужны ли дорожки? |
|---|---|
| 1 (одна система) | Не нужны — достаточно plain Activity Diagram |
| 2–5 | Да — дорожки улучшают читаемость |
| 6+ | Подумайте — слишком много дорожек усложняют диаграмму. Разбейте процесс на подпроцессы |
Типичная ошибка: Путают Swimlane и Partition. В UML:
- Swimlane — распределение по ролям
- Partition — любое группирование (по отделам, по системам, по городам...)
В PlantUML разницы нет — и то, и другое задаётся через |Имя|.
4. Пример: Activity Diagram для авторизации пользователя
4.1. Постановка задачи
Спроектируем процесс входа пользователя в личный кабинет интернет-магазина с использованием двухфакторной аутентификации (2FA).
Участники:
- Пользователь — человек, пытающийся войти в систему
- Система — серверная часть приложения
Описание процесса:
- Пользователь открывает страницу входа
- Пользователь вводит логин и пароль
- Система проверяет формат введённых данных
- Если формат невалидный — система показывает сообщение об ошибке, пользователь вводит заново (цикл до 3 попыток)
- Если формат валидный — система проверяет логин/пароль в БД
- Если логин/пароль неверны — система увеличивает счётчик неудачных попыток; если попытки исчерпаны (3+) — блокирует аккаунт на 15 минут
- Если логин/пароль верны — система проверяет, включена ли 2FA
- Если 2FA выключена — система создаёт сессию и перенаправляет в личный кабинет
- Если 2FA включена — система отправляет одноразовый код (TOTP) на email/телефон пользователя
- Пользователь вводит код из письма
- Система проверяет код:
- Код верен — создаёт сессию, перенаправляет в личный кабинет
- Код неверен — предлагает ввести код заново (ещё 2 попытки)
- Параллельно с шагами 9–11: система логирует попытку входа (дата, время, IP-адрес)
- Если пользователь ввёл неверный код 3 раза — система блокирует вход на 30 минут и отправляет предупреждение на email
4.2. Разбор — почему здесь Activity, а не BPMN?
Этот процесс — технический алгоритм:
- Есть циклы (повтор ввода при ошибке)
- Есть счётчики (3 попытки)
- Есть ветвления с проверкой формата данных
- Нет бизнес-ролей (только Пользователь и Система)
- Нет таймеров «ожидание 3 дня» (таймер блокировки — это пауза, а не бизнес-таймер)
Для технического алгоритма Activity Diagram подходит идеально. BPMN здесь был бы избыточен — нам не нужны events, pools, message flows.
4.3. PlantUML-код
@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBorderColor #333333
title Процесс авторизации пользователя с 2FA
|Пользователь|
start
:Открыть страницу входа;
:Ввести логин и пароль;
|Система|
:Проверить формат данных;
if (Формат валиден?) then (Нет)
:Показать сообщение об ошибке;
|Пользователь|
:Ввести данные заново;
note right: Счётчик попыток\nограничен тремя
|Система|
else (Да)
endif
:Проверить логин/пароль в БД;
if (Логин/пароль верны?) then (Нет)
:Увеличить счётчик\nнеудачных попыток;
if (Попыток >= 3?) then (Да)
:Заблокировать аккаунт\nна 15 минут;
stop
else (Нет)
|Пользователь|
:Ввести данные заново;
|Система|
endif
else (Да)
:Проверить настройки 2FA;
endif
if (2FA включена?) then (Нет)
:Создать сессию пользователя;
|Пользователь|
:Войти в личный кабинет;
stop
else (Да)
:Отправить одноразовый\nкод (TOTP);
|Пользователь|
:Ввести код из письма;
|Системa|
fork
:Логировать попытку\nвхода (IP, время);
fork again
if (Код TOTP верен?) then (Да)
:Создать сессию пользователя;
|Пользователь|
:Войти в личный кабинет;
stop
else (Нет)
:Увеличить счётчик\nневерных кодов;
if (Попыток TOTP >= 3?) then (Да)
:Заблокировать вход\nна 30 минут;
:Отправить предупреждение\nна email;
stop
else (Нет)
|Пользователь|
:Ввести код заново;
|Система|
endif
endif
end fork
@enduml
4.4. Анализ диаграммы
Что можно увидеть на этой Activity Diagram:
- Дорожки (Swimlanes): Пользователь и Система — чёткое разделение, кто что делает
- Decision Node: 4 ромба (формат, пароль, 3 попытки, 2FA, TOTP)
- Fork/Join: Параллельный поток логирования (начинается вместе с отправкой кода, но не блокирует основной процесс — здесь Fork не требует Join, так как логирование может завершиться после входа)
- Merge: Слияние путей после проверки формата (валидный/невалидный)
- Циклы: Возврат на ввод данных при неверном формате и неверном пароле
- Flow Final: Ветка логирования может завершиться отдельно (неявно — через stop/end)
Замечание по нотации: В диаграмме есть место, которое стоило бы обсудить — блокировка аккаунта завершает процесс (stop). Но что, если пользователь одновременно пытается войти из другого браузера? На этом уровне абстракции это допустимо. Для production-диаграммы можно добавить ноту.
5. Продвинутые элементы
5.1. Accept Event Action — ожидание события
Нотация: скруглённый прямоугольник с волнистой верхней частью («вогнутый» уголок).
Назначение: процесс останавливается и ждёт наступления внешнего события — получения сообщения, срабатывания таймера, изменения состояния.
Примеры:
- «Ожидать подтверждение оплаты от платёжного шлюза»
- «Ждать 15 минут до автоматической отмены заказа»
- «Получить ответ от службы доставки»
@startuml
start
:Отправить запрос на оплату;
:Ожидать ответ от\nплатёжного шлюза;
if (Ответ получен?) then (Да)
:Обработать результат;
stop
else (Нет)
:Повторить запрос;
endif
@enduml
5.2. Send Signal Action — отправка сигнала
Нотация: скруглённый прямоугольник с «выпуклым» уголком (зубчатый край).
Назначение: отправить сигнал (сообщение) другому процессу или системе.
Пример: после создания заказа отправить сигнал в CRM-систему.
5.3. Interruptible Region — прерываемый регион
Нотация: пунктирный прямоугольник с зигзагообразным краем («молния»).
Назначение: область, в которой все действия могут быть прерваны наступлением определённого события.
Пример — оплата бронирования:
┌─ Interruptible Region ──────────────────────┐
│ │
│ ● → Отправить счёт → Ожидать оплату │
│ │
│ (если в течение 15 минут оплата не прошла — │
│ регион прерывается, заказ отменяется) │
│ │
└──────────────────────────────────────────────┘
↑
│ Событие-прерыватель: Accept Event Action
│ «Таймер 15 минут истёк»
Важно: после прерывания региона управление переходит к действию, соединённому с прерывателем (например, «Отменить заказ»).
5.4. Exception Handler — обработчик исключения
Нотация: «молния» (зигзаг), прикреплённая к действию.
Назначение: если действие выбросило исключение (ошибку выполнения), управление переходит к обработчику.
Пример:
⬭ Отправить запрос
│
[исключение: сеть недоступна]
▼
⬭ Записать ошибку в лог
5.5. Object Node — передача данных
Нотация: прямоугольник (как класс, но без стереотипа).
Назначение: показать, какие данные передаются между действиями.
Три варианта:
- Object Node на потоке — прямоугольник на стрелке:
→ [Данные] → - Object Node как вход/выход — прямоугольник, из которого выходит/в который входит поток
- Data Store — прямоугольник с загнутым углом и стереотипом
<<datastore>>
6. Пошаговый метод построения Activity Diagram
Шаг 0. Определите, нужна ли Activity Diagram вообще
Задайте себе вопросы:
- Процесс сложнее 5 шагов? → Да
- Есть ветвления? → Да (если есть)
- Есть параллельные действия? → Да
- Участвуют разные роли? → Да
Если ответ «Да» на 2+ вопроса — рисуйте Activity.
Шаг 1. Определите границы процесса
| Что | Результат |
|---|---|
| Триггер | Что запускает процесс? Событие? Действие пользователя? |
| Результат | Что считается успешным завершением? Аварийным? |
| Участники | Роли/системы, которые участвуют |
Запишите: Initial Node → список Swimlane → Final Node (успех) + Final Node (ошибка)
Шаг 2. Нарисуйте Happy Path (основной сценарий)
Это самый простой сценарий — «всё идеально, без ошибок».
- Initial Node ●
- Действие → Действие → Действие (последовательно)
- Final Node ◉
Правило: Happy Path должен быть хорошо виден — обычно его рисуют как прямую линию сверху вниз или слева направо.
Шаг 3. Добавьте Decision Node
Для каждого шага, где есть альтернативы, поставьте ромб.
Техника: пройдите по каждому действию и спросите: «А что, если...?»
- Что, если данные неверны?
- Что, если пользователь не найден?
- Что, если система недоступна?
Результат: Decision Node с условиями на выходах.
Шаг 4. Добавьте Fork/Join
Для действий, которые можно выполнять параллельно, поставьте Fork.
Признаки параллельности:
- Действия независимы друг от друга
- Действия не используют результат друг друга
- Действия можно выполнять в любом порядке
Результат: Чётко обозначенные параллельные блоки.
Шаг 5. Проверьте на полноту
Чек-лист:
- Все стрелки куда-то ведут (нет «висящих»)
- У каждого Decision Node есть условия на выходах
- Условия покрывают все случаи (есть
[else]) - Каждый Fork имеет соответствующий Join (если нужно)
- Merge стоит там, где альтернативные пути сходятся
- Swimlane отражают реальные роли
- Нет тупиков (действий, которые никуда не ведут)
- Основной сценарий (Happy Path) интуитивно виден
7. Продвинутые паттерны Activity Diagram
7.1. Pipeline Pattern (конвейер)
Несколько этапов, где каждый этап — отдельный шаг, данные передаются по цепочке.
● → ⬭ Шаг 1 → ⬭ Шаг 2 → ⬭ Шаг 3 → ◉
[data1] [data2] [result]
Где используется: ETL-процессы, обработка документов, CI/CD пайплайны.
7.2. Retry Pattern (повтор с счетчиком)
● → ⬭ Выполнить запрос
│
◇ ── [успех] ──→ ◉
│
└── [ошибка] ──→ ◇ ── [попыток < 3] ──→ ⬭ Выполнить запрос (снова)
│
└── [попыток ≥ 3] ──→ ⬭ Записать ошибку → ◉
Где используется: HTTP-запросы, отправка писем, работа с внешними API.
7.3. Compensating Transaction Pattern (компенсация)
Если одно из параллельных действий не удалось — откатываем предыдущие.
Fork ─┬─→ ⬭ Забронировать отель ──┐
│ │
└─→ ⬭ Забронировать билет ──┤
│
[ошибка брони билета]
│
▼
⬭ Отменить отель → ◉
Где используется: Saga-процессы, распределённые транзакции, booking-системы.
7.4. Timeout Pattern (тайм-аут в Activity)
Activity не имеет нативного таймера (в отличие от BPMN). Тайм-аут моделируется через Interruptible Region + Accept Event Action.
● → ⬭ Отправить запрос
│
Установить таймер 5 сек
│
◇ ── [ответ получен] ──→ ⬭ Обработать → ◉
│
└── [таймер сработал] ──→ ⬭ Тайм-аут → ◉
8. Activity Diagram в PlantUML
8.1. Два синтаксиса
PlantUML поддерживает два синтаксиса для Activity Diagram:
| Аспект | Старый синтаксис (deprecated) | Новый синтаксис (рекомендуемый) |
|---|---|---|
| Старт | (*) |
start |
| Действие | --> "текст" |
:текст; |
| Условие | if ("условие") then ("да") |
if (условие) then (да) else (нет) endif |
| Параллельно | ` | ---` |
| Дорожки | partition name { } |
` |
Мы используем новый синтаксис (c официального сайта plantuml.com/activity-diagram-beta).
8.2. Справочник синтаксиса
| Что хотим | Синтаксис PlantUML |
|---|---|
| Начало | start |
| Конец (все потоки) | stop |
| Конец (один поток) | end |
| Действие | :Имя действия; |
| Решение (if) | if (условие) then (ветка А) else (ветка Б) endif |
| Проверка-цикл | repeat :действие; repeat while (условие) |
| Параллельные (fork) | fork \n :действие1; \n fork again \n :действие2; \n end fork |
| Дорожка | ` |
| Разделитель дорожек | ` |
| Примечание | note right :текст / note left / floating note |
| Цвет действия | :текст; #цвет |
| Группа (partition) | partition Имя { \n :действие; \n } |
| Деталь (описание) | :текст;\nnote right: детали |
| Стрелка с текстом | ->текст; для указания на стрелке |
8.3. Примеры конструкций
Decision (if-else):
if (x > 0?) then (Да)
:Положительное число;
else (Нет)
:Отрицательное или ноль;
endif
Decision с несколькими ветками:
if (Тип документа?) then (Акт)
:Обработать акт;
elseif (Счёт)
:Обработать счёт;
elseif (Накладная)
:Обработать накладную;
else (Другое)
:Вернуть на доработку;
endif
Цикл repeat-while:
repeat
:Ввести данные;
repeat while (Данные корректны?) is (Нет)
->Да; :Обработать;
Fork (параллельные потоки):
fork
:Отправить email;
fork again
:Создать задачу в CRM;
fork again
:Обновить статус;
end fork
8.4. Полный пример с авторизацией (из раздела 4)
Полный код PlantUML для диаграммы авторизации уже приведён в разделе 4.3. Его можно скопировать и скомпилировать на plantuml.com или в локальном PlantUML.
Как скомпилировать:
- Онлайн: plantuml.com → вставить код → Render
- VS Code: установить плагин "PlantUML" → Alt+D
- CLI:
plantuml diagram.puml -tpng
9. Типичные ошибки и как их избежать
Ошибка 1: Fork вместо Decision
Ситуация: разработчик рисует Fork, потому что «нужно выбрать один из двух путей».
⚠️ Неправильно: ✅ Правильно:
Fork Decision
┌──> A ┌──> A
──┤ ────◇──┤
└──> B └──> B
Все пути идут Только один путь
одновременно по условию
Как запомнить: Fork — «делаем всё сразу», Decision — «выбираем одно».
Ошибка 2: Нет Merge (стрелки пересекаются)
⚠️ Неправильно:
⬭ A ──→ ◇ ──→ ⬭ C
│
└──→ ⬭ B
Стрелка от Decision идёт прямо в C — непонятно, что пути сходятся
✅ Правильно:
⬭ A ──→ ◇ ──→ ⬭ B ──→ ◇ ──→ ⬭ C
│ ↑
└───────────────┘
Merge Node явно показывает слияние путей
Ошибка 3: Действие слишком крупное
⚠️ Неправильно: «Обработать заказ» — слишком абстрактно
✅ Правильно:
• Проверить наличие на складе
• Рассчитать стоимость с доставкой
• Создать заказ в БД
• Отправить подтверждение
Правило: одно действие = одна атомарная операция, понятная читателю без дополнительных пояснений.
Ошибка 4: Нет покрытия «иначе»
⚠️ Неправильно: ✅ Правильно:
◇ ◇
│ │
├─ [сумма > 0] ├─ [сумма > 0]
└─ ├─ [сумма = 0]
└─ [else / отрицательная]
На каждом Decision Node условия на выходах должны покрывать 100% возможных значений. Если условие — if (сумма > 0), то ветка else должна обрабатывать случай сумма ≤ 0.
Ошибка 5: Fork без Join
⚠️ Неправильно:
Fork ─┬─→ A ────→ ◉
└─→ B ──→ ⊗
• Join нет вообще
• Activity Final (◉) на одной ветке
завершит ВЕСЬ процесс, включая B
✅ Правильно (если нужно дождаться обеих веток):
Fork ─┬─→ A ──┐
│ ├── Join → C → ◉
└─→ B ──┘
Исключение: если одна из параллельных веток — «логирование» или «уведомление», которое может завершиться после основного потока, Fork без Join допустим.
Ошибка 6: Бесконечный цикл без выхода
⚠️ Опасно:
repeat
:Ввести пин-код;
:Проверить пин-код;
repeat while (Неверный?) is (Да)
→ Нет
• Нет счётчика попыток!
• Если пользователь никогда не введёт верный код — цикл бесконечен
✅ Правильно:
:Сбросить счётчик попыток;
repeat
:Ввести пин-код;
:Проверить пин-код;
:Увеличить счётчик;
repeat while (Неверный И попыток < 3?) is (Да)
→ Нет
:Заблокировать карту;
10. Чек-лист: готовая Activity Diagram
| № | Критерий | Как проверить |
|---|---|---|
| 1 | Initial Node есть | Визуально |
| 2 | Final Node есть | Визуально |
| 3 | Нет «висящих» стрелок | Каждая стрелка ведёт к узлу |
| 4 | Decision Node — 1 вход, N выходов | Счёт |
| 5 | На выходах Decision — условия в [] |
Проверить тексты |
| 6 | Условия покрывают 100% случаев | Анализ |
| 7 | Fork — 1 вход, N выходов | Счёт |
| 8 | Join — N входов, 1 выход | Счёт |
| 9 | Swimlane соответствуют ролям из Use Case | Сверка с моделью актёров |
| 10 | Happy Path визуально выделен | Визуально (обычно левый верх — правый низ) |
| 11 | Альтернативные пути есть | Проверить ошибки, исключения |
| 12 | Нет дублирования действий | Проверить названия |
11. Вопросы для самопроверки
- В чём разница между Decision Node и Fork Node? Приведите пример для каждого.
- Что такое Merge Node и чем он отличается от Join Node?
- Когда вы используете Activity Diagram, а когда — BPMN? Назовите три критерия выбора.
- Что произойдёт, если на Activity Diagram поставить два Activity Final Node (◉)?
- Можно ли на Activity Diagram смоделировать тайм-аут? Если да — как?
- Что такое Interruptible Region? Придумайте пример из своей работы.
- Как в PlantUML задать три параллельных потока?
- Сколько дорожек оптимально для Activity Diagram? Почему?
- В чём опасность отсутствия Merge Node на диаграмме?
- Как смоделировать цикл с ограничением на 3 попытки в Activity Diagram?
12. Практическое задание
Кейс: Процесс обработки возврата товара в интернет-магазине
Описание процесса:
- Покупатель открывает страницу заказа в личном кабинете
- Покупатель нажимает «Оформить возврат»
- Система проверяет, прошло ли не более 14 дней с момента получения заказа
- Если срок возврата истёк (> 14 дней) — система показывает сообщение «Срок возврата истёк», процесс завершается
- Если срок не истёк — система запрашивает причину возврата и состояние товара
- Покупатель заполняет форму возврата (причина, описание дефекта, фото — опционально)
- Система создаёт заявку на возврат
- Параллельно выполняются два действия:
- Система отправляет уведомление менеджеру склада
- Система отправляет покупателю инструкцию по возврату (адрес, правила упаковки)
- Покупатель отправляет товар (передаёт курьеру или приносит в пункт выдачи)
- Менеджер склада проверяет товар при получении:
- Если товар соответствует заявлению — запускается процедура возврата денег
- Если товар не соответствует (следы эксплуатации, отсутствие комплектации) — запускается процедура отказа в возврате
- Процедура возврата денег:
- Система создаёт запрос на перевод денег в платёжную систему
- Платёжная система обрабатывает возврат (3–5 рабочих дней по регламенту — используйте Accept Event Action для ожидания)
- Система отправляет покупателю уведомление о возврате денег
- Процедура отказа в возврате:
- Система отправляет покупателю уведомление об отказе с указанием причины
- Менеджер склада оформляет обратную отправку товара покупателю
Задание 1. Постройте Activity Diagram
Составьте Activity Diagram процесса возврата товара.
Требования:
- Используйте 3 дорожки: Покупатель, Система, Менеджер склада
- Минимум 3 Decision Node
- Минимум 1 Fork / Join
- Используйте Accept Event Action для ожидания обработки платежной системой
- Отразите все альтернативные пути (срок истёк / не истёк, товар соответствует / не соответствует)
Задание 2. PlantUML-код
Напишите полный PlantUML-код этой Activity Diagram. Используйте:
|Имя роли|для дорожекif / elseif / else / endifдля ветвленийfork / fork again / end forkдля параллельных потоковrepeat / repeat whileесли есть циклы (в задании их нет, но можно добавить обработку нескольких товаров в одном возврате для практики)note rightдля поясненийstopиendдля завершения
Задание 3. Анализ ошибок
Даны 3 фрагмента Activity Diagram с логическими ошибками. Найдите и опишите каждую ошибку:
Фрагмент A:
● → ⬭ Отправить запрос
│
◇ ── [успех] ──→ ⬭ Обработать → ◉
│
└── [ошибка] ──→ ⊗
Фрагмент B:
● → ⬭ Подготовить данные
│
▬ ──┬──→ ⬭ Этап 1
│
└──→ ⬭ Этап 2
│
◇ ── [готово] ──→ ◉
Фрагмент C:
● → ⬭ А
│
◇ ── [да] ──→ ⬭ B
│ │
└── [нет] ────→┘
│
▼
◉
Задание 4. Выбор нотации (эссе)
Ответьте письменно (5–7 предложений):
«Вам нужно смоделировать процесс обработки страхового случая в страховой компании. Процесс сложный: есть таймеры (3 дня на рассмотрение), параллельные проверки, компенсационные действия при отказе, и в будущем процесс будет передан в BPM-движок для исполнения. Какую нотацию вы выберете — Activity Diagram или BPMN? Почему?»
13. Дополнительные материалы
- Книга: Martin Fowler — «UML Distilled», 3-е издание, глава 10 «Activity Diagrams» (базовое, но чёткое введение)
- Спецификация: OMG UML 2.5.1, раздел 17 «Actions» и раздел 15.3 «Activity Diagrams» (формальное определение — для самых пытливых)
- PlantUML: plantuml.com/activity-diagram-beta — официальная документация нового синтаксиса
- Инструмент: draw.io / diagrams.net — бесплатный редактор с поддержкой UML Activity (File → New → UML → Activity Diagram)
- Статья: «Choosing between BPMN and UML Activity Diagrams» by Bruce Silver (ключевое различие — исполняемость)
- Видео: «UML Activity Diagram Tutorial» на Lucidchart YouTube channel (15 минут)
- Шпаргалка: «Activity Diagram Cheat Sheet» — одностраничная памятка с элементами и правилами (можно сгенерировать в draw.io)
- Паттерны: Enterprise Integration Patterns (Hohpe, Woolf) — многие паттерны (Pipeline, Retry, Compensating Transaction) естественно ложатся на Activity Diagram
Следующий урок: 04.04 — Sequence Diagram (Диаграмма последовательности)