Лестница моделирования: онтологии, C4, Event Storming, FSM
Весь раздел мы проектировали системы словами и кодом: границы, контракты, потоки событий. Пока команда умещается за одним столом, этого хватает. Потом появляется второй стол, новый разработчик, аудитор из прошлого урока, и оказывается, что устройство системы нужно показывать, а не пересказывать. Тут у моделирования всплывает дурная репутация: толстые UML-альбомы, устаревшие в день печати, и архитектор, рисующий квадратики вместо работы. Репутация заслуженная, но выводы из неё обычно делают неверные. Проблема не в моделях, а в неумении выбирать уровень формальности. Этот урок и есть лестница таких уровней: от глоссария до конечного автомата, с правилом, какую ступень брать под какой вопрос.
Лестница уровней
Вспомни определение из урока про моделирование: модель это упрощение реальности, сохраняющее то, что важно для конкретного вопроса. Из него следует главное правило урока: сначала вопрос, потом нотация. Разные вопросы требуют разной строгости, а строгость стоит денег: и при создании модели, и, что важнее, при каждом изменении системы, после которого модель надо обновлять. Получается лестница: чем выше, тем точнее ответы и дороже поддержка.
| Ступень | Отвечает на вопрос | Цена |
|---|---|---|
| Глоссарий | как мы называем вещи | копейки |
| ER, концептуальная модель | какие сущности и как связаны | низкая |
| Event Storming | что происходит в домене | один воркшоп |
| C4 | из чего состоит система | низкая, если as code |
| State diagram | в каких состояниях живёт сущность | средняя |
| BPMN, DMN | как течёт процесс, как принимается решение | высокая |
| TLA+ | не нарушается ли инвариант | очень высокая |
Выбирай самую дешёвую ступень, которая отвечает на твой вопрос. Вопрос «почему сотрудники площадки и кассиры называют одно и то же слово билет разными вещами» решается глоссарием, и рисовать для него C4 бессмысленно. Вопрос «может ли возврат и продажа одного места столкнуться» глоссарием не решается, тут нужна как минимум статусная модель.
Почему же «нарисовать всё в UML» не сработало? UML предлагал четырнадцать видов диаграмм и культуру вокруг них: CASE-инструменты, генерацию кода из моделей и обратно. Индустрия проверила и оставила от всего этого два жанра: диаграммы структуры (близкие к ER) и диаграммы последовательности. Остальное умерло от главной болезни моделей: модель, которую не обновляют, врёт, и врёт авторитетно, ведь она выглядит как документация. Отсюда второе правило урока: заводя модель, заводи и процесс её обновления. Лучший из известных процессов: хранить модель как текст рядом с кодом и ревьюить диффом, к этому вернёмся на ступени C4.
Онтологии: от реальности к схеме
Нижние ступени лестницы отвечают на вопрос «о чём вообще наша система». Путь сверху вниз выглядит так: есть реальность (живые люди покупают билеты в кассах), есть её осмысление командой (мы решили, что для нас существуют события, площадки и заказы), и есть онтология, это осмысление, записанное явно. Самая дешёвая онтология тебе уже знакома: глоссарий, единый язык из обзора DDD. Слово, которое команда употребляет в двух значениях, это не лингвистика, а будущий баг: «билет» как право прохода и «билет» как PDF с QR-кодом ведут себя по-разному при возврате.
Дальше понятия обрастают структурой, и тут индустрия данных давно разделила три уровня модели:
| Уровень | Язык | Пример для афиши |
|---|---|---|
| CDM | сущности и связи словами | билет принадлежит заказу и даёт право на место |
| LDM | атрибуты, ключи, кардинальности | у Ticket есть order_id, seat_id, уникальность места внутри события |
| PDM | таблицы и индексы СУБД | tickets с bigint-ключами, уникальный индекс (event_id, seat_id), партиции по сезону |
Ценность не в каждом уровне по отдельности, а в дисциплине перехода:
спор о том, может ли заказ существовать без билетов, это спор уровня
CDM, и решать его выбором между NULL и NOT NULL на уровне PDM,
минуя обсуждение, означает зашить случайное бизнес-решение в схему.
Классические нотации этих уровней: ER-диаграммы и IDEF1X; идея
доводилась до предела в
MDA,
где из моделей собирались генерировать весь код. Генерация не
взлетела, лестница осталась.
C4: четыре зума
Поднимаемся от данных к системе целиком. C4 победила UML на поле «показать устройство системы» одним приёмом: она узаконила зум. Вместо одной диаграммы обо всём четыре уровня, каждый для своей аудитории:
- Context. Система как чёрный ящик: кто пользователи, какие внешние системы вокруг. Аудитория: все, включая бизнес.
- Container. Из каких деплоймент-юнитов система состоит: приложения, базы, очереди, воркеры. Аудитория: инженеры, включая соседние команды.
- Component. Что внутри одного контейнера: модули и их связи. Аудитория: команда этого контейнера.
- Code. Классы и функции. Этот уровень почти никогда не рисуют руками: он устаревает быстрее всех, а при нужде генерируется из кода.
Система как чёрный ящик: люди слева, внешние системы справа. Что внутри, уровень не говорит, и в этом его сила.
- аудитория
- все, включая бизнес
- вопрос уровня
- кто пользователи и какие системы вокруг
- устаревает
- редко
- аудитория
- инженеры, включая соседние команды
- вопрос уровня
- из каких деплоймент-юнитов состоит система
- устаревает
- при смене инфраструктуры
- аудитория
- команда этого контейнера
- вопрос уровня
- какие модули внутри и как они связаны
- устаревает
- при каждом крупном рефакторинге
- аудитория
- никто: при нужде генерируется
- вопрос уровня
- классы и функции
- устаревает
- быстрее всех
Пройди по табам слева направо и следи за строкой «аудитория»: каждый зум сужает её. Если на одной диаграмме встретились Зритель, Postgres и класс OrderService, уровни смешаны, и диаграмма отвечает на все вопросы сразу, то есть ни на один.
Главный анти-паттерн ровно один: смешать уровни на одной диаграмме, где рядом живут «Зритель», «Postgres» и «класс OrderService». Такая диаграмма не отвечает ни на один вопрос, потому что отвечает на все сразу.
Вторая причина победы C4: она дружит с diagrams as code. Диаграмма как текст в репозитории лечит болезнь устаревания наполовину: она хотя бы меняется тем же процессом, что и код, и ревьюер видит диф архитектуры. Context и Container афиши на Structurizr DSL умещаются в экран:
workspace {
model {
visitor = person "Зритель"
manager = person "Менеджер площадки"
afisha = softwareSystem "Афиша" {
web = container "Веб-приложение" "Astro SSR"
api = container "API" "Node.js"
db = container "База" "PostgreSQL"
worker = container "Биллинг-воркер" "обработчик очереди"
}
payments = softwareSystem "Платёжный провайдер" "внешняя система"
idp = softwareSystem "IdP клиента" "Okta, Entra"
visitor -> web "покупает билеты"
manager -> web "управляет событиями"
web -> api "HTTP"
api -> db "SQL"
worker -> payments "создаёт списания"
payments -> api "webhooks"
idp -> api "SAML, SCIM"
}
}
Инструмент рендерит из этого и Context (системы и люди), и
Container (содержимое afisha). Альтернативы по вкусу: Mermaid
рисуется прямо в GitHub и в маркдауне, PlantUML ветеран с самым
богатым синтаксисом, D2 самый приятный глазу. Где такие диаграммы
живут и как соотносятся с остальной архитектурной документацией,
разобрано в
уроке про карту документов.
дальше после входа
Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.
Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.