UML для аналитика: какие диаграммы полезны и как их читают разработчики
Аналитик рисует схему не потому, что «так положено по регламенту», и не потому, что документ без картинки выглядит бедно. Схема — это инструмент сжатия неоднозначности. У каждого предложения на русском языке есть десятки допустимых прочтений; у стрелки на sequence-диаграмме их два-три. Разница между этими числами и есть вся польза моделирования.
Эта статья — не пересказ спецификации OMG. Из четырнадцати типов диаграмм UML 2.5.1 аналитику в реальной работе нужны пять, и то не целиком. Разберём эти пять до уровня «понимаю нотацию, вижу дефект требования на схеме, знаю, что спросит разработчик».
Предполагается, что вы уже прошли https://courses.digitable.life/post/systems-analysis/02-requirements-types/ (виды требований) и https://courses.digitable.life/post/systems-analysis/03-documentation/ (user story, use case, критерии приёмки). Здесь мы берём те же требования и переводим их в графическую форму — там, где текст перестаёт справляться.
1. Первый принцип: зачем вообще картинка
1.1. Естественный язык — плохой контейнер для требований
Возьмём фразу из реального ТЗ:
После оплаты заказ уходит в доставку.
Одно предложение, семь слов. Вопросы, которые оно оставляет открытыми:
- «После оплаты» — после нажатия кнопки, после ответа банка «авторизовано» или после списания? Между ними бывает несколько часов.
- «Уходит» — это система создаёт задание на сборку, или отправляет событие в WMS, или курьеру падает push?
- Что происходит, если банк ответил «авторизовано», а склад в этот момент недоступен?
- Можно ли отменить заказ в промежутке?
- А если оплата частичная — бонусами плюс картой?
- Кто узнаёт, что заказ ушёл в доставку, — покупатель, менеджер, оба?
- Что если платёж авторизован, но capture не прошёл?
Каждый из этих вопросов — потенциальный баг, дефект интеграции или спор на приёмке. Текст не заставляет вас на них отвечать: предложение выглядит законченным и грамматически корректным.
Схема заставляет. Чтобы нарисовать sequence-диаграмму, вы обязаны назвать участников, порядок сообщений и ветки. Чтобы нарисовать state machine — перечислить состояния и события. Пустое место на схеме видно; пустое место в предложении — нет. Моделирование — это способ сделать незнание видимым.
1.2. Диаграмма — это язык с типами
Стрелка в PowerPoint не значит ничего: она значит то, что имел в виду автор. Стрелка в UML типизирована. Сплошная с закрашенным наконечником — синхронный вызов, отправитель ждёт. Пунктирная — возврат управления. Открытый наконечник — асинхронное сообщение. Ромб у класса — композиция, и это значит, что часть не живёт без целого.
Когда все участники обсуждения знают типы, спор становится содержательным: «здесь у тебя синхронный вызов внешнего шлюза внутри транзакции — мы так не сможем, будет блокировка». Без типов спор превращается в «а я думал, ты имел в виду другое».
1.3. Три режима использования UML
Мартин Фаулер в «UML Distilled» вводит различение, которое снимает большинство религиозных споров о UML (UmlMode):
| Режим | Что это | Кому нужно | Инструмент |
|---|---|---|---|
| Sketch (эскиз) | Выборочная схема, чтобы объяснить идею и обсудить | Аналитику — 90% времени | Доска, Excalidraw, Miro, mermaid |
| Blueprint (чертёж) | Полная и точная модель, по которой можно кодировать | Иногда: контракты интеграций, сложные автоматы | PlantUML в репозитории, Enterprise Architect |
| Programming language | Модель, из которой генерируется код (MDA) | Практически никому | MDA-инструменты |
Третий режим — это мечта 2000-х, которая не сбылась: генерация продакшн-кода из моделей осталась в узких нишах вроде встраиваемых систем и телекома. Первые два — живая ежедневная практика. Аналитик, который рисует эскиз, но защищает его как чертёж («тут нельзя менять, это по стандарту»), вредит проекту сильнее, чем тот, кто не рисует вовсе.
1.4. Когда достаточно доски, а когда нужен документ
Практическое правило: уровень формальности схемы определяется не важностью фичи, а сроком жизни решения и ценой ошибки.
Читается так:
- Правый верхний угол — контракты и автоматы, которые переживут вас в этой компании и цена ошибки в которых измеряется деньгами клиентов. Здесь нужен версионируемый артефакт с явным владельцем и датой ревью.
- Левый верхний — короткоживущее, но опасное: разбор инцидента, выбор схемы интеграции на воркшопе. Рисуем на доске, но письменно фиксируем принятое решение — иначе через три недели восстановить логику будет невозможно.
- Левый нижний — 60% работы. Доска, разговор, фото в чат. Оформлять это в документ — чистые потери; такая схема устареет раньше, чем её согласуют.
- Правый нижний — долгоживущий справочник (словарь статусов, карта интеграций). Держим в вики, обновляем по мере изменений, но без тяжёлых согласований.
Ключевая ошибка новичка — тащить всё в правый верхний угол «чтобы было надёжно». Результат: пятидесятистраничная спецификация, которую никто не читает, и команда, которая всё равно спрашивает вас в чате.
2. Карта: что из UML действительно нужно
Таблица соответствия «вопрос — диаграмма» — то, что стоит держать в голове:
| Вопрос, на который отвечаем | Диаграмма | Основной читатель |
|---|---|---|
| Кто пользуется системой и что входит в её ответственность? | Use case | Заказчик, менеджер, новый разработчик |
| В каком порядке системы обмениваются сообщениями и что при ошибке? | Sequence | Backend, интеграторы, тестировщик |
| Как устроен процесс с ролями и ветвлениями? | Activity (дальше — BPMN) | Бизнес-заказчик, поддержка |
| Какие состояния бывают у заказа и какие переходы разрешены? | State machine | Backend, тестировщик, поддержка |
| Какие сущности есть в предметной области и как связаны? | Class (концептуальная) | Все, особенно новички |
| Из каких блоков состоит система и где границы интеграции? | Component | Архитектор, DevOps |
Если вопроса нет — диаграмма не нужна. Это главный фильтр против «схем для красоты».
3. Use case diagram: она про границы, а не про поток
Самая недопонятая диаграмма UML. Аналитики рисуют её как декомпозицию функций, а потом удивляются, что разработчики её игнорируют.
3.1. Что она на самом деле сообщает
Три вещи, и только их:
- Где проходит граница системы. Прямоугольник — то, что мы строим и за что отвечаем. Всё, что снаружи, — чужое: другая команда, внешний вендор, живой человек.
- Кто с ней взаимодействует. Актор — это роль, а не должность и не человек. «Покупатель» — роль; «Иван Петрович из отдела закупок» — нет. Внешняя система тоже актор.
- Какие цели акторы достигают. Овал — цель, достижение которой имеет ценность и имеет наблюдаемый результат.
Чего диаграмма НЕ показывает: порядок, условия, данные, время. Это не блок-схема. Если вам нужен порядок — вам нужна другая диаграмма.
3.2. Тест на настоящий вариант использования
Алистер Кокберн в «Writing Effective Use Cases» предлагает проверку уровня цели: спросите про овал — «если актор уйдёт домой сразу после этого, он будет доволен?»
- «Оформить заказ» — да, цель достигнута. Настоящий use case.
- «Ввести адрес доставки» — нет, это шаг. Не use case.
- «Валидировать email» — нет, это вообще внутреннее поведение системы.
- «Управлять товарами» — нет, это раздел меню, замаскированный под цель.
Последний пункт — самая частая болезнь. Овалы вида «Управлять X», «Работа с Y», «Администрирование Z» превращают диаграмму в карту разделов интерфейса. Разработчику она не даёт ничего: из «Управлять товарами» не выводится ни одного требования.
3.3. include и extend: направления, которые все путают
«include»— стрелка от базового сценария к включаемому. Означает: базовый всегда выполняет этот кусок. «Оплатить заказ» всегда включает «Проверить лимит по антифроду».«extend»— стрелка от расширяющего к базовому. Означает: расширяющий иногда вклинивается в базовый в определённой точке. «Списать бонусы» иногда вклинивается в оплату.
Направления противоположны, и это ловушка. Практический совет: если сомневаетесь — не используйте ни то, ни другое. Три овала без стереотипов читаются лучше, чем пятнадцать с перепутанными стрелками. Фаулер прямо пишет, что злоупотребление include/extend превращает диаграмму в функциональную декомпозицию — то есть в то, чем она не является.
3.4. Как это читает разработчик
Разработчик смотрит на use case diagram ровно тридцать секунд и извлекает две вещи:
- Список внешних систем — значит, будут интеграции, значит, нужны контракты, ретраи и обработка недоступности. Каждый внешний актор — это будущая работа, которой нет в оценке.
- Роли — значит, будет авторизация и разграничение прав. Три актора в системе, где заложена одна роль, — это переделка модели доступа.
Дальше он идёт читать текстовые use case и user story. Диаграмма — оглавление, а не содержание; тело сценария живёт в тексте, см. https://courses.digitable.life/post/systems-analysis/03-documentation/.
4. Sequence diagram: главный инструмент аналитика
Если из всей статьи вы возьмёте одну диаграмму — берите эту. Она отвечает на вопрос, из-за которого срываются сроки: кто кому что шлёт, в каком порядке, и что происходит, когда что-то идёт не так.
4.1. Нотация, которая реально несёт смысл
- Линия жизни — участник обмена во времени, время идёт сверху вниз. Участник — это система, сервис, компонент или человек. Не таблица БД и не класс.
- Полоса активации — период, когда участник держит управление. Полезно, чтобы увидеть: «мы держим HTTP-соединение открытым пока внешний банк думает 40 секунд».
- Сплошная стрелка с закрашенным наконечником — синхронный вызов, отправитель ждёт ответа.
- Пунктир — возврат: ответ, результат, ошибка.
- Открытый наконечник — асинхронное сообщение: отправил и пошёл дальше.
- Комбинированные фрагменты —
alt(ветвление),opt(необязательный блок),loop(цикл),par(параллельно),break(прерывание). Их пять и они покрывают почти всё.
Различие синхронного и асинхронного — не украшение. Это архитектурное требование: асинхронность означает, что вам нужен способ узнать результат позже (webhook, поллинг, очередь), а значит — состояние «ожидаем подтверждения», таймаут и обработка «результат так и не пришёл».
4.2. Плохая диаграмма
Так рисуют в 80% случаев:
Формально всё верно. Практически — бесполезно. Что здесь не так:
- Участник «Система» — это не участник, это всё что угодно. Фронт, бэкенд, очередь и БД склеены в один прямоугольник, а вся сложность живёт как раз между ними.
- Нет ни одной ветки ошибки. Банк отвечает «успех» — всегда. В проде банк отвечает отказом, требует 3DS, отваливается по таймауту и присылает ответ дважды.
- Нет данных. «Провести платёж» — с какими полями? Идемпотентный ключ есть?
- Нет времени. Сколько ждём ответа? Что делаем на 30-й секунде?
- Нет состояния заказа. В какой момент заказ становится оплаченным для пользователя?
Такая схема не сокращает неоднозначность — она её маскирует, создавая иллюзию проработки.
4.3. Хорошая диаграмма
отменять нельзя — деньги могли уйти P->>P: пометить платёж как unknown P-->>O: pending O-->>W: 202 Accepted, статус processing W-->>U: «Проверяем оплату, обновим статус» end deactivate G deactivate P G-)P: webhook payment.captured P->>P: проверить подпись и дедуплицировать по txn_id P-)Q: событие PaymentCaptured Q-)O: PaymentCaptured O->>O: заказ в состояние paid O-)Q: событие OrderPaid deactivate O Note over O,Q: доставка подписана на OrderPaid,
синхронного вызова склада нет
Что изменилось и почему это важно каждому участнику команды:
- Участники разделены — видно, что фронт получает
202, а не200: значит, нужен UI «обрабатываем», значит, дизайнеру нужна ещё одна экранная форма. Одна стрелка породила требование к интерфейсу. - Есть ветка таймаута — и она вскрыла неявное требование: при неизвестном статусе платежа нельзя ни подтверждать, ни отменять заказ. Это отдельное состояние, а не «ошибка».
- Есть идемпотентность —
Idempotency-Keyи дедупликация webhook поtxn_id. Без этого двойное нажатие кнопки списывает деньги дважды. Подробнее про гарантии доставки — в https://courses.digitable.life/post/distributed-systems/09-idempotency-and-delivery/. - Асинхронная развязка со складом — открытый наконечник и очередь вместо прямого вызова. Это решение стоит денег и времени, и его нужно проговорить, а не «подразумевать».
Каждая стрелка на такой диаграмме превращается в строчку API-контракта. О том, как из этого получается спецификация эндпоинтов и форматов, — в https://courses.digitable.life/post/systems-analysis/07-api-analysis/.
4.4. Чек-лист самопроверки sequence-диаграммы
Прежде чем показывать схему команде, пройдите по списку:
- Каждый участник — реальная развёртываемая единица? Не «Система», не «Бэкенд вообще».
- Есть хотя бы одна ветка неуспеха? Если нет — вы описали happy path и назвали его требованием.
- Что делает система, если ответа не пришло совсем? Таймаут — не ошибка, а третий исход.
- Повторная отправка того же сообщения безопасна? Если нет — где ключ идемпотентности?
- Сообщение может прийти дважды или не в том порядке? Для очередей — почти всегда да.
- Есть ли указание времени там, где оно критично? «Ждём до 10 с» — требование, а не деталь.
- Видно ли, в какой момент меняется состояние ключевой сущности?
- Один уровень абстракции? Нельзя в одной схеме мешать «Пользователь нажал кнопку» и «SELECT из таблицы orders».
Пункты 3–5 — это ровно те места, где рождаются продовые инциденты, и ровно те, которые не попадают в текстовые требования.
5. Activity diagram: поток работ с ролями
Activity diagram — это блок-схема с дорожками. Аналитику она нужна, когда важен порядок работ и распределение ответственности между ролями, а не обмен сообщениями между системами.
Нотация минимальна: закрашенный круг — начало, прямоугольники со скруглениями — действия, ромб — решение, толстая полоса — fork/join (распараллеливание и синхронизация), круг с обводкой — конец. Дорожки (swimlanes) делят схему по ролям.
mermaid не поддерживает UML activity напрямую, но flowchart с subgraph в роли дорожек
читается практически так же:
к перепродаже?"} C3["Вернул в оборот"] C4["Списал"] end subgraph fin["Финансы"] D1["Инициировал возврат средств"] D2["Деньги ушли покупателю"] end A1 --> B1 A2 --> B1 B1 --> B2 B2 -->|"упаковка цела"| B3 B2 -->|"повреждена"| E1["Спор: фото, акт, решение менеджера"] E1 --> B3 B3 --> C1 C1 --> C2 C2 -->|"да"| C3 C2 -->|"нет"| C4 C3 --> D1 C4 --> D1 D1 --> D2
Три вещи, которые эта схема сразу вскрывает:
- Узел «Спор» — про него в исходных требованиях не было ни слова. Он появился, потому что ромб «упаковка цела» обязал нас назвать вторую ветку.
- Дорожка «Отдел качества» — там сидят живые люди, а значит, у процесса есть SLA, очередь и рабочие часы. Это нефункциональные требования, см. https://courses.digitable.life/post/systems-analysis/08-nonfunctional/.
- Возврат денег происходит одинаково в обеих ветках — стоит спросить бизнес, точно ли это так: обычно «списали» и «вернули в оборот» имеют разные последствия для суммы возврата.
5.1. Activity или BPMN?
Практическое различение:
- Activity diagram — когда процесс в основном внутри системы и читатели технические.
- BPMN — когда процесс охватывает людей, отделы, внешние организации, таймеры, эскалации, и читатели бизнесовые. У BPMN богаче семантика событий и она понятна процессным аналитикам без объяснений.
Для сквозных бизнес-процессов почти всегда выигрывает BPMN — это тема следующей статьи, https://courses.digitable.life/post/systems-analysis/05-bpmn/.
Типичные ошибки в activity-диаграммах: ромб с одной исходящей веткой (значит, решения нет); fork без join (параллельные ветки, которые никогда не сходятся, — процесс не может завершиться); дорожка «Система», в которой происходит вся содержательная работа; и схема на две страницы, которую невозможно охватить взглядом. Если схема не помещается на экран — это две схемы.
6. State machine: самый недооценённый инструмент
Диаграмма состояний — лучший из известных мне детекторов неявных требований. Причина простая: она требует перечислить все состояния и все события, а декартово произведение этих множеств немедленно показывает дыры.
6.1. Жизненный цикл заявки
Схема уже задала три вопроса, которых не было в исходном ТЗ:
- Можно ли отозвать заявку, пока она на проверке? На схеме такого перехода нет — это решение или пропуск?
- Что происходит с заявкой в состоянии Исполняется, если исполнение сорвалось? Нет перехода в «Отклонена» и нет состояния «Приостановлена».
- Кто и когда предупреждает заявителя о том, что через 14 дней заявка отзовётся автоматически? Из перехода по таймеру вытекает целая подсистема уведомлений.
6.2. Матрица переходов — механический способ найти дыры
Постройте таблицу «состояния × события» и заполните каждую ячейку. Пустые ячейки — это или осознанный запрет, или неявное требование.
| Событие \ Состояние | Черновик | На проверке | Требует уточнения | Одобрена | Исполняется |
|---|---|---|---|---|---|
| Отправить | → На проверке | запрет | запрет | запрет | запрет |
| Запрос данных | запрет | → Требует уточнения | запрет | запрет | запрет |
| Отозвать заявителем | → Отозвана | ? | ? | ? | ? |
| Решение положительное | запрет | → Одобрена | запрет | запрет | запрет |
| Таймер 14 дней | ? | ? | → Отозвана | запрет | запрет |
| Отмена администратором | ? | ? | ? | ? | ? |
Шесть вопросительных знаков — шесть требований, которые иначе всплыли бы на приёмке или в проде. «Отмена администратором» вообще не упоминалась в постановке, но она точно понадобится службе поддержки на второй неделе эксплуатации.
Это и есть механический способ бороться с неявными требованиями: не полагаться на озарение, а заполнить таблицу.
6.3. Проверка автомата алгоритмом
Если состояний больше десятка, проверять руками неэффективно. Автомат — это ориентированный граф, и к нему применимы обычные алгоритмы обхода.
Псевдокод:
вход: множество состояний S, начальное s0, множество финальных F,
переходы T как список (из, событие, в)
1. достижимые = BFS(s0, T) # обход в ширину по рёбрам
2. недостижимые = S \ достижимые # дефект: состояние-призрак
3. для каждого s из достижимых:
если нет исходящих переходов и s не в F: # дефект: тупик
сообщить о тупике
4. для каждой пары (s, e) из достижимые × События:
если переходов нет: # дыра или осознанный запрет
требовать явного решения
если переходов больше одного и нет guard-условий:
сообщить о недетерминизме
Реализация:
from collections import defaultdict, deque
def analyze(states, initial, finals, transitions):
"""transitions: список кортежей (из_состояния, событие, в_состояние).
Возвращает словарь с найденными дефектами автомата.
"""
out = defaultdict(list) # состояние -> список (событие, цель)
events = set()
for src, ev, dst in transitions:
out[src].append((ev, dst))
events.add(ev)
# 1. достижимость: обычный BFS, O(V + E)
reachable, queue = {initial}, deque([initial])
while queue:
cur = queue.popleft()
for _, dst in out[cur]:
if dst not in reachable:
reachable.add(dst)
queue.append(dst)
# 2. тупики: нефинальное состояние без выхода
dead_ends = [s for s in reachable if not out[s] and s not in finals]
# 3. недетерминизм: одна пара (состояние, событие) ведёт в разные цели
nondet = []
for s in reachable:
by_event = defaultdict(set)
for ev, dst in out[s]:
by_event[ev].add(dst)
nondet += [(s, ev) for ev, targets in by_event.items() if len(targets) > 1]
# 4. непокрытые пары: кандидаты в неявные требования
uncovered = [
(s, ev)
for s in sorted(reachable)
for ev in sorted(events)
if not any(e == ev for e, _ in out[s])
]
return {
"unreachable": sorted(set(states) - reachable),
"dead_ends": sorted(dead_ends),
"nondeterministic": sorted(nondet),
"uncovered": uncovered,
}
Сложность: BFS даёт O(V + E) по времени и O(V) по памяти, где V — число состояний,
E — число переходов. Построение матрицы покрытия — O(V * K) по времени и памяти,
где K — число различных событий. Для реальных автоматов (десятки состояний, десятки событий)
это доли миллисекунды, а список uncovered — готовая повестка встречи с заказчиком.
Приём: выгружайте переходы из таблицы в CSV, гоняйте скрипт в CI и падайте, если появились новые непокрытые пары без явного решения. Это превращает модель в живой артефакт.
6.4. Состояние против флага: где ломается на практике
Три классических дефекта.
Дефект 1. Состояние размазано по флагам. В БД есть is_paid, is_shipped, is_cancelled,
is_returned. Четыре булевых поля дают 16 комбинаций, из которых осмысленны 6. Остальные
десять рано или поздно возникнут — и никто не знает, что система должна в них делать.
Лечение: одно поле status с явным перечислением плюс автомат переходов.
Дефект 2. Два независимых измерения склеены в один статус. Оплата и доставка меняются
независимо: заказ может быть оплачен и не отгружен, отгружен и не оплачен (постоплата).
Попытка выразить это одним статусом даёт комбинаторный взрыв: paid_shipped,
unpaid_shipped, paid_packing. Правильное решение — два параллельных автомата.
В UML это ортогональные регионы композитного состояния:
Два независимых измерения, четыре плюс три состояния вместо двенадцати комбинаций. Идея пришла из статьи Дэвида Харела Statecharts: A Visual Formalism for Complex Systems (1987) — она же лежит в основе UML state machine.
Дефект 3. Два источника истины о состоянии. Статус хранится в вашей БД и во внешней системе, и они расходятся. Требование, которое отсюда следует и которое почти всегда забывают: кто главный, как часто сверяем, что делаем при расхождении.
6.5. Из автомата — прямо в критерии приёмки
Каждый переход — это готовый сценарий проверки. Отсюда критерии приёмки пишутся почти механически:
Функционал: Отзыв заявки заявителем
Сценарий: заявку можно отозвать до принятия решения
Допустим заявка находится в состоянии "На проверке"
Когда заявитель нажимает "Отозвать"
Тогда заявка переходит в состояние "Отозвана"
И проверяющий получает уведомление об отзыве
И повторная отправка этой же заявки невозможна
Сценарий: отозвать одобренную заявку нельзя
Допустим заявка находится в состоянии "Одобрена"
Когда заявитель нажимает "Отозвать"
Тогда система отвечает ошибкой "Заявка уже одобрена"
И состояние заявки не меняется
Второй сценарий — про запрещённый переход. Их обычно не пишут, и именно они всплывают в проде. Подробнее о технике — https://courses.digitable.life/post/testing/14-tdd-and-bdd/ и https://courses.digitable.life/post/systems-analysis/12-acceptance/.
7. Class diagram как концептуальная модель домена
Аналитик рисует class diagram не для программистов и не про классы кода. Он рисует концептуальную модель: словарь предметной области, где у каждого термина есть связи и кратности.
7.1. Что здесь несёт требования
Кратности — это требования, а не украшение. Прочитаем схему вслух:
Order "1" *-- "1..*" OrderLine— заказ состоит минимум из одной строки. Значит, пустой заказ создать нельзя, значит, нужна валидация, значит, «удалить последнюю позицию» должно либо блокироваться, либо отменять заказ. Одно требование выведено из символа1..*.Order "1" o-- "0..*" Payment— платежей у заказа может быть несколько. Значит, поддерживаем частичные оплаты и доплаты, значит, сумма заказа и сумма платежей — разные величины, которые нужно сверять.OrderLine "0..*" --> "1" Productи поле «цена на момент заказа» — цена копируется в строку заказа. Это прямое требование: изменение цены в каталоге не должно менять сумму уже оформленного заказа. Забытое, оно даёт классический баг «сумма старого заказа поехала после переоценки».
Композиция против агрегации. Закрашенный ромб (*--) — композиция: строка заказа
не существует вне заказа, удаление заказа удаляет строки, границы транзакции совпадают.
Пустой ромб (o--) — агрегация: платёж связан с заказом, но живёт своей жизнью и в некоторых
системах вообще хранится в другом сервисе. Для разработчика это разница между каскадным
удалением и внешней ссылкой, а для аналитика — между «удалили заказ, история платежей пропала»
и «осталась». Про то, как это превращается в границы агрегатов, — https://courses.digitable.life/post/ddd/03-tactical-building-blocks/.
7.2. Class diagram — не ERD
Частая путаница. Та же область в виде ERD выглядит иначе:
Отличия, которые важно понимать:
| Class diagram (концептуальная) | ERD (логическая или физическая) | |
|---|---|---|
| Про что | Понятия предметной области | Таблицы и колонки |
| Есть поведение | Может быть (операции) | Нет |
| Связь многие-ко-многим | Рисуется напрямую | Требует таблицы связи |
| Наследование | Есть | Нет, эмулируется тремя способами |
| Кто читает | Бизнес, аналитик, вся команда | Backend, DBA |
Правило: обсуждать с бизнесом — по концептуальной модели, проектировать хранение —
по ERD. Показывать заказчику схему с PK, FK и numeric(12,2) — способ гарантированно
не получить обратной связи. Подробнее о моделировании данных — https://courses.digitable.life/post/systems-analysis/06-data-modeling/
и https://courses.digitable.life/post/databases/01-relational-model/.
8. Component и deployment: когда нужны аналитику
Эти две диаграммы аналитику нужны редко, но в двух ситуациях без них тяжело.
Component diagram — когда вы работаете с системой из многих сервисов и нужно понять, кто чем владеет. Практическая ценность: карта того, какие команды придётся согласовывать. Три компонента в схеме — три владельца, три очереди задач, три расписания релизов. Часто вместо UML используют модель C4 Саймона Брауна (c4model.com): она проще, специально придумана для разговоров о структуре системы и лучше читается нетехническими стейкхолдерами.
Deployment diagram — когда требования упираются в физику: данные не могут покидать периметр банка, мобильное приложение работает офлайн, отчёты строятся в другом дата-центре. Из размещения выводятся нефункциональные требования — задержки, доступность, локализация данных по требованиям регуляторов.
Если ваша задача — фича внутри одного сервиса, обе диаграммы избыточны. Для контекста об архитектурных решениях см. https://courses.digitable.life/post/architecture-patterns/11-architecture-decisions/ и https://courses.digitable.life/post/architecture/requirements/.
9. Что ломается чаще всего и как диаграммы это ловят
Соберём главное в один раздел. Вот четыре типовых дефекта требований и конкретный инструмент против каждого.
9.1. Неявные требования
Симптом. «Ну это же очевидно» на планировании. Через месяц — баг с приоритетом «критичный».
Почему возникает. Эксперт предметной области не осознаёт своё знание как знание. Для него «просроченная заявка автоматически закрывается» — фон, как воздух.
Инструмент. Матрица «состояния × события» из раздела 6.2 и ветки alt на sequence-диаграмме.
Оба приёма работают одинаково: они создают структуру, в которой пустота видна.
Практика встречи. Не спрашивайте «есть ли ещё требования?» — ответ всегда «нет». Покажите матрицу и спросите: «вот эта клетка. Заявка одобрена, приходит отмена от админа. Что делаем?» На конкретную клетку эксперт отвечает всегда.
9.2. Противоречия между стейкхолдерами
Симптом. Две правды. Отдел продаж уверен, что скидка применяется к сумме заказа; финансы — что к каждой позиции. Оба правы в своей картине мира, оба искренни.
Почему возникает. Разные роли живут в разных частях процесса и видят только свой кусок.
Инструмент. Нарисуйте обе версии, рядом, на одном экране, и покажите обеим сторонам одновременно. Противоречие в тексте прячется в разных абзацах разных документов; противоречие на двух схемах видно за пять секунд.
Дальше — не вы решаете, кто прав. Вы фиксируете расхождение, показываете последствия каждой версии (цифрами: «в варианте A средний чек падает на X, в варианте B ломается выгрузка в 1С») и передаёте решение владельцу продукта. Механика согласований — в https://courses.digitable.life/post/systems-analysis/10-stakeholders/.
9.3. «Хотелки» без задачи
Симптом. «Сделайте кнопку экспорта в Excel на этом экране». Без контекста, без цели, без объяснения.
Инструмент. Use case: попробуйте вписать просьбу в форму «актор — цель — результат». Если не вписывается — цели нет, есть предполагаемое решение.
Два вопроса, которые почти всегда работают:
- «Кто и как часто будет этим пользоваться?» — если ответ «ну, иногда, наверное, все», у запроса нет владельца.
- «Что человек делает с этим файлом после выгрузки?» — здесь обычно вскрывается настоящая задача: «сводит с отчётом из другой системы». А настоящее решение — не кнопка экспорта, а сверка внутри продукта или интеграция.
Диаграмма здесь работает как фильтр: решение, которое невозможно нарисовать как чей-то сценарий с результатом, скорее всего, решает несуществующую задачу.
9.4. Требования, которые невозможно проверить
Симптом. «Система должна работать быстро и быть удобной». Спорить не с чем, проверить нельзя, на приёмке — конфликт.
Инструмент. Правило: каждая стрелка на схеме должна быть наблюдаемым событием. Если вы не можете сказать, как зафиксировать факт этого сообщения (лог, запись в БД, HTTP-запрос, изменение статуса на экране), — требование непроверяемо.
Пример превращения:
| Непроверяемое | Проверяемое |
|---|---|
| «Система быстро отвечает» | «95-й перцентиль ответа POST /orders/{id}/pay не более 800 мс при 50 RPS» |
| «Пользователь понимает, что происходит» | «В состоянии processing на экране показан статус и оценка времени; статус обновляется не реже раза в 5 с» |
| «Платежи не теряются» | «Каждому webhook соответствует ровно одна запись payment; повтор с тем же txn_id не создаёт новой» |
Заметьте, что все три «проверяемые» формулировки выведены прямо из sequence-диаграммы раздела 4.3: стрелка, состояние, дедупликация. Схема не просто иллюстрирует требование — она подсказывает, где его измерять. Развёрнуто — в https://courses.digitable.life/post/systems-analysis/08-nonfunctional/.
10. Diagram-as-code и жизненный цикл схемы
10.1. Проблема протухания
Диаграмма в Visio, лежащая в приложении к письму от прошлого марта, — хуже, чем отсутствие диаграммы: она врёт с видом авторитетного документа. Разработчик один раз обжигается и перестаёт верить всем вашим схемам, включая свежие.
Лечение: схема живёт в текстовом виде рядом с тем, что она описывает, и меняется тем же пул-реквестом. Тогда изменение кода без изменения схемы видно на ревью.
PlantUML — самый распространённый выбор для UML-as-code:
@startuml
autonumber
actor Покупатель as U
participant "Order Service" as O
participant "Payment Service" as P
U -> O : POST /orders/{id}/pay
activate O
O -> P : authorize(order_id, amount)
activate P
alt авторизация успешна
P --> O : authorized
else отказ банка
P --> O : declined(reason)
O -> O : заказ в состояние payment_failed
end
deactivate P
deactivate O
@enduml
Mermaid (mermaid.js.org) слабее по возможностям UML, но рендерится прямо в GitHub, GitLab и большинстве вики без плагинов — для эскизов этого достаточно. PlantUML (plantuml.com) берут, когда нужны полноценные комбинированные фрагменты, use case и точная UML-нотация.
10.2. Правила гигиены
- У каждой сохранённой схемы есть владелец и дата последнего пересмотра. Нет владельца — удаляйте: она уже врёт или начнёт завтра.
- Схема на доске — валидный артефакт с коротким сроком годности. Сфотографировали, кинули в тред задачи, записали текстом принятое решение. Переносить в «красивый» вид не нужно — нужно зафиксировать вывод.
- Не более одного уровня абстракции на схему. Смешение «пользователь нажал» и «вызвали хранимую процедуру» делает схему нечитаемой для обеих аудиторий сразу.
- Схема без вопроса — мусор. Перед рисованием сформулируйте вопрос, на который она отвечает. Не сформулировали — не рисуйте.
- Схема, которая не помещается на экран, не читается. Разбивайте: одна общая карта плюс несколько детальных.
11. Как это читает разработчик
Полезно понимать, что происходит в голове у того, кому вы показываете схему. Разработчик не любуется — он ищет работу, которую придётся сделать, и риски, за которые придётся отвечать.
Что он выцепляет за первые тридцать секунд:
- Внешние участники. Каждый — интеграция: контракт, аутентификация, ретраи, обработка недоступности, мониторинг. То, что для вас одна стрелка, для него — неделя.
- Асинхронные стрелки. Значит, очередь или webhook; значит, дедупликация, порядок сообщений и «а что если событие не пришло».
- Ветки ошибок. Их отсутствие — красный флаг: «аналитик не думал о проде».
- Изменения состояния. Где меняется статус — там транзакция, гонки и вопрос «а если два пользователя одновременно?».
- Кратности
0..*и1..*. Каждая звёздочка — пагинация, лимиты, производительность. - Хранение и время жизни данных. «Сохраняет адреса» — сколько, как долго, что с ними при удалении аккаунта.
Что делает схему бесполезной в его глазах: участник «Система»; happy path без исключений; смешанные уровни абстракции; овалы «Управлять чем-то»; и схема, противоречащая коду, который он вчера писал.
Хороший приём: показывая схему, начните не с неё, а с вопроса — «я хочу проверить, что правильно понял вот этот кусок». Тогда схема воспринимается как приглашение к правке, а не как спущенное сверху требование. Разработчик добавит на неё три стрелки, и это ровно то, что вам нужно: он знает про систему то, чего не знаете вы.
12. Мини-итог
- Диаграмма — не иллюстрация к тексту, а инструмент, который делает незнание видимым. Пустое место на схеме заметно, пустое место в предложении — нет.
- Из UML аналитику нужны пять диаграмм: use case (границы и роли), sequence (взаимодействие и ошибки), activity (поток работ), state machine (жизненный цикл), class (концептуальная модель домена).
- Sequence-диаграмма без веток ошибок и таймаутов описывает не систему, а мечту о ней.
- Матрица «состояния × события» — механический способ найти неявные требования; она проверяется
скриптом за
O(V + E)и может жить в CI. - Кратности и типы связей в концептуальной модели — это требования:
1..*запрещает пустой заказ, композиция определяет каскадное удаление. - Уровень формальности выбирается по сроку жизни решения и цене ошибки, а не по важности фичи. Большая часть схем должна остаться фотографией доски.
- Схему показывают как гипотезу о понимании, а не как утверждённый документ. Правки от команды — это успех встречи, а не провал вашей работы.
Источники
- Martin Fowler. UML Distilled, 3rd ed. — martinfowler.com/books/uml.html; ключевые заметки: UmlMode, UmlAsSketch.
- OMG. Unified Modeling Language, v2.5.1 — omg.org/spec/UML/2.5.1 (первоисточник нотации; читать целиком не нужно, но полезно проверять спорные детали).
- Alistair Cockburn. Writing Effective Use Cases — alistair.cockburn.us (уровни целей, форматы текстовых сценариев).
- David Harel. Statecharts: A Visual Formalism for Complex Systems, 1987 — sciencedirect.com (иерархические и ортогональные состояния, основа UML state machine).
- Karl Wiegers, Joy Beatty. Software Requirements, 3rd ed. — karlwiegers.com (модели анализа как дополнение к текстовым требованиям).
- Simon Brown. The C4 model for visualising software architecture — c4model.com.
- PlantUML — plantuml.com/ru/sequence-diagram; Mermaid — mermaid.js.org.
Что дальше
Диаграммы UML хорошо описывают системы и сущности, но плохо — сквозные бизнес-процессы с людьми, отделами, таймерами и эскалациями. Для этого есть отдельная нотация, у которой своя семантика событий и свои характерные ошибки: Моделирование процессов: BPMN, нотации, типичные ошибки в схемах.