Activity Diagram (Диаграмма деятельности)

Урок 3 из 5

Урок 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

  1. Описание алгоритма (ветвления, циклы, параллельные вычисления)
  2. Техническая документация (как работает внутренний модуль системы)
  3. Проектная документация для разработчиков (Activity привычнее для IT)
  4. Быстрое прототипирование процесса на доске/в PlantUML
  5. Описание вариантов использования (Use Case) — один Use Case → одна Activity Diagram

2.5. Когда BPMN однозначно лучше Activity

  1. Процесс будет исполняться в Camunda / ELMA / другие BPM-движки
  2. Нужны сложные события (таймеры «ожидание 3 дня», сообщения между процессами, ошибки с компенсациями)
  3. Сложные взаимодействия между участниками (пулы с потоками сообщений)
  4. Требуется формальный регламент («Утверждаю» — подпись)
  5. Процесс содержит итеративный цикл ревью с возвратом на доработку

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).

Участники:

  • Пользователь — человек, пытающийся войти в систему
  • Система — серверная часть приложения

Описание процесса:

  1. Пользователь открывает страницу входа
  2. Пользователь вводит логин и пароль
  3. Система проверяет формат введённых данных
  4. Если формат невалидный — система показывает сообщение об ошибке, пользователь вводит заново (цикл до 3 попыток)
  5. Если формат валидный — система проверяет логин/пароль в БД
  6. Если логин/пароль неверны — система увеличивает счётчик неудачных попыток; если попытки исчерпаны (3+) — блокирует аккаунт на 15 минут
  7. Если логин/пароль верны — система проверяет, включена ли 2FA
  8. Если 2FA выключена — система создаёт сессию и перенаправляет в личный кабинет
  9. Если 2FA включена — система отправляет одноразовый код (TOTP) на email/телефон пользователя
  10. Пользователь вводит код из письма
  11. Система проверяет код:
    • Код верен — создаёт сессию, перенаправляет в личный кабинет
    • Код неверен — предлагает ввести код заново (ещё 2 попытки)
  12. Параллельно с шагами 9–11: система логирует попытку входа (дата, время, IP-адрес)
  13. Если пользователь ввёл неверный код 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:

  1. Дорожки (Swimlanes): Пользователь и Система — чёткое разделение, кто что делает
  2. Decision Node: 4 ромба (формат, пароль, 3 попытки, 2FA, TOTP)
  3. Fork/Join: Параллельный поток логирования (начинается вместе с отправкой кода, но не блокирует основной процесс — здесь Fork не требует Join, так как логирование может завершиться после входа)
  4. Merge: Слияние путей после проверки формата (валидный/невалидный)
  5. Циклы: Возврат на ввод данных при неверном формате и неверном пароле
  6. 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 — передача данных

Нотация: прямоугольник (как класс, но без стереотипа).

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

Три варианта:

  1. Object Node на потоке — прямоугольник на стрелке: → [Данные] →
  2. Object Node как вход/выход — прямоугольник, из которого выходит/в который входит поток
  3. Data Store — прямоугольник с загнутым углом и стереотипом <<datastore>>

6. Пошаговый метод построения Activity Diagram

Шаг 0. Определите, нужна ли Activity Diagram вообще

Задайте себе вопросы:

  • Процесс сложнее 5 шагов? → Да
  • Есть ветвления? → Да (если есть)
  • Есть параллельные действия? → Да
  • Участвуют разные роли? → Да

Если ответ «Да» на 2+ вопроса — рисуйте Activity.

Шаг 1. Определите границы процесса

Что Результат
Триггер Что запускает процесс? Событие? Действие пользователя?
Результат Что считается успешным завершением? Аварийным?
Участники Роли/системы, которые участвуют

Запишите: Initial Node → список Swimlane → Final Node (успех) + Final Node (ошибка)

Шаг 2. Нарисуйте Happy Path (основной сценарий)

Это самый простой сценарий — «всё идеально, без ошибок».

  1. Initial Node ●
  2. Действие → Действие → Действие (последовательно)
  3. 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.

Как скомпилировать:

  1. Онлайн: plantuml.com → вставить код → Render
  2. VS Code: установить плагин "PlantUML" → Alt+D
  3. 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. Вопросы для самопроверки

  1. В чём разница между Decision Node и Fork Node? Приведите пример для каждого.
  2. Что такое Merge Node и чем он отличается от Join Node?
  3. Когда вы используете Activity Diagram, а когда — BPMN? Назовите три критерия выбора.
  4. Что произойдёт, если на Activity Diagram поставить два Activity Final Node (◉)?
  5. Можно ли на Activity Diagram смоделировать тайм-аут? Если да — как?
  6. Что такое Interruptible Region? Придумайте пример из своей работы.
  7. Как в PlantUML задать три параллельных потока?
  8. Сколько дорожек оптимально для Activity Diagram? Почему?
  9. В чём опасность отсутствия Merge Node на диаграмме?
  10. Как смоделировать цикл с ограничением на 3 попытки в Activity Diagram?

12. Практическое задание

Кейс: Процесс обработки возврата товара в интернет-магазине

Описание процесса:

  1. Покупатель открывает страницу заказа в личном кабинете
  2. Покупатель нажимает «Оформить возврат»
  3. Система проверяет, прошло ли не более 14 дней с момента получения заказа
  4. Если срок возврата истёк (> 14 дней) — система показывает сообщение «Срок возврата истёк», процесс завершается
  5. Если срок не истёк — система запрашивает причину возврата и состояние товара
  6. Покупатель заполняет форму возврата (причина, описание дефекта, фото — опционально)
  7. Система создаёт заявку на возврат
  8. Параллельно выполняются два действия:
    • Система отправляет уведомление менеджеру склада
    • Система отправляет покупателю инструкцию по возврату (адрес, правила упаковки)
  9. Покупатель отправляет товар (передаёт курьеру или приносит в пункт выдачи)
  10. Менеджер склада проверяет товар при получении:
    • Если товар соответствует заявлению — запускается процедура возврата денег
    • Если товар не соответствует (следы эксплуатации, отсутствие комплектации) — запускается процедура отказа в возврате
  11. Процедура возврата денег:
    • Система создаёт запрос на перевод денег в платёжную систему
    • Платёжная система обрабатывает возврат (3–5 рабочих дней по регламенту — используйте Accept Event Action для ожидания)
    • Система отправляет покупателю уведомление о возврате денег
  12. Процедура отказа в возврате:
    • Система отправляет покупателю уведомление об отказе с указанием причины
    • Менеджер склада оформляет обратную отправку товара покупателю

Задание 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 (Диаграмма последовательности)

📚 Материалы модуля

🖼️ Схема и инфографика

🎬 Видео-лекция

🎬 UML Универсальные чертежи

📄 Дополнительные материалы (PDF)

📄The UML Blueprint
Скачать
Спросить ИИ