коротко

Все записи справочника — это отдельные навыки. Здесь они собираются в один проект. Мы ведём одну систему — MeetRoom, внутренний сервис бронирования переговорок — от первого разговора с заказчиком до эксплуатации в проде, и на каждом шаге показываем, какой артефакт аналитик производит и в какой записи разобран нужный навык. Путь: понять бизнес-смысл → выявить требования у стейкхолдеров → собрать SRS → спроектировать (HLD/LLD, зафиксировать выборы в ADR) → описать модель данных и жизненный цикл брони → задать API с ошибками и авторизацией → нарисовать интеграции (календарь по вебхуку) → продумать миграции, эксплуатацию и метрики. Это та самая сквозная нить, которой не хватает, когда теорию учат темами вразнобой: тут видно, как один документ перетекает в другой и почему порядок именно такой.

Когда я учился на аналитика, теория лежала в голове по полочкам: вот требования, вот нотации, вот API, вот базы данных. А потом меня посадили на реальный проект, и оказалось, что полочки не помогают — нужно было пройти путь от «нам нужна штука для переговорок» до работающего сервиса, и я не понимал, что за чем идёт и где какой навык включается. Полочки — это словарь, а проект — это связный текст. Эта запись — связный текст: одна система, проведённая через весь справочник от начала до конца.

Возьмём MeetRoom — внутренний веб-сервис, где сотрудники бронируют переговорки офиса. Та же система, на которой построены примеры в записях про SRS, HLD/LLD и авторизацию. Здесь мы соберём все её куски в один маршрут.

Шаг 1. Зачем это вообще: бизнес-контекст

Любой проект начинается не с требований, а с вопроса «зачем». Прежде чем проектировать MeetRoom, надо понять, какую боль он лечит и сколько она стоит: сотрудники тратят время на поиск свободной комнаты, переговорки занимают «по памяти» и конфликтуют, секретарь ведёт расписание в табличке и ошибается. Это деньги — потерянные часы и сорванные встречи. Как считать эту ценность и почему «зачем» важнее «как» — в записи про бизнес-контекст и деньги. И сразу понимаем, в каком окружении работаем и кто в команде сделает MeetRoom — про роли в записи кто все эти люди.

Чтобы «зачем» не повисло в воздухе, кладу на стол прикидку. В офисе ~200 сотрудников, средняя ставка ~1500 ₽/час. По интервью каждый теряет ~10 минут в день на поиск комнаты и разруливание конфликтов «кто здесь сидит» — это 200 × (10/60) × 1500 ≈ 50 000 ₽ в день, около миллиона в месяц сгоревшего времени. Цифра грубая, но именно она превращает «было бы удобно» в «вот сколько стоит ничего не делать» — и именно её спросит спонсор, прежде чем дать бюджет.

Шаг 2. Выявить требования, а не записать

Заказчик — офис-менеджер — приходит с готовым решением: «сделайте табличку со списком комнат и кнопкой занять». Наша работа — не записать это, а докопаться до проблемы: что на самом деле болит. Это выявление требований: интервью, наблюдение за тем, как комнаты бронируют сейчас, «5 почему». Параллельно составляем карту тех, кто влияет на продукт и может зарубить его на приёмке, — про это запись стейкхолдеры и RACI. Здесь всплывает безопасник с требованием «сотрудник не должен видеть чужие встречи» — стейкхолдер, которого легко пропустить, а его «нет» дороже всего.

Артефакт этого шага — не пересказ интервью, а вскрытый корень. «5 почему» по запросу заказчика выглядят так: хочу табличку с кнопкой «занять» → почему? → чтобы не приходили в занятую комнату → почему приходят? → бронь живёт в голове секретаря → почему в голове? → нет общего источника правды → почему нет? → никто не отвечает за расписание комнат. Корень — не «нет таблички», а «нет единого источника правды о занятости слота». Это и есть настоящее требование, и оно сразу диктует, что слот занятости — атомарная сущность, а не строка в Excel.

До того как писать SRS, решаем, что вообще делаем в первую очередь: бронирование и просмотр — да, оплата платных комнат и интеграция со СКУД — потом. Это MVP и приоритизация, а отделить «что выяснить» от «что строить» помогает дискавери против деливери. И сразу честно оцениваем объём — диапазоном, а не точкой: про это оценка задач.

Шаг 3. Зафиксировать: SRS

Выявленное превращаем в документ, иначе оно не существует. Для MeetRoom это SRS (спецификация требований, SRS) — полная спецификация: цель, границы (что в скоупе, что нет), акторы (сотрудник, офис-менеджер, внешний календарь), функциональные требования с ID (создать бронь, защита от двойного бронирования) и нефункциональные (NFR — нефункциональные требования) с числами (сетка доступности < 800 мс, доступность 99.5%, «сотрудник видит только свои брони»). Как из выявленного собрать читаемый документ — в записи как написать ТЗ; разница между функциональными и нефункциональными требованиями — в FR против NFR, а отдельные сценарии описываем как user story и use case.

Чтобы не оставаться на словах, вот как корень из шага 2 ложится в две строки SRS:

IDТипТребование
FR-03функциональноеСистема отклоняет создание брони, если запрошенный слот пересекается по времени с уже подтверждённой бронью той же комнаты.
NFR-02нефункциональноеСетка доступности комнат на день отдаётся за < 800 мс на 95-м перцентиле при нагрузке 50 RPS.

Видно, чем они отличаются: FR — что система делает (проверяемо да/нет), NFR — насколько хорошо (проверяемо числом). Размытое «должно быть быстро» из NFR-02 превратилось в «< 800 мс на p95» — то, что можно поставить в alert.

Шаг 4. Спроектировать: HLD, LLD, ADR

SRS говорит «что», теперь «как». Сначала крупными блоками — HLD (крупный дизайн, high-level, HLD/LLD): веб-приложение, бэкенд MeetRoom, база, внешний SSO, внешний календарь, и поток создания брони между ними. Потом детали — LLD (детальный дизайн, low-level): схема таблицы броней, контракт POST /bookings, защита от двойного бронирования через уникальное ограничение в БД. А каждый неочевидный выбор фиксируем в ADR (журнал архитектурных решений, ADR), чтобы через полгода никто не «улучшил» решение обратно в баг. Какую диаграмму для чего рисовать — в записи про нотации BPMN, UML, C4.

ADR-001: PostgreSQL, а не Mongo — готовый ответ

Контекст: ядро MeetRoom — защита от двойного бронирования слота. Решение: хранилище — PostgreSQL. Почему: создание брони — это атомарная проверка-и-вставка против конфликта слота: «никто не занял этот промежуток — и тут же занимаю его сам». В реляционной БД это даётся ограничением из коробки (UNIQUE на пару room_id + слот, а для пересекающихся интервалов — EXCLUDE USING gist): два параллельных запроса на один слот — один проходит, второй получает отказ на уровне БД, без гонки. Документная БД (Mongo) гарантирует атомарность в пределах одного документа, но «нет ли пересечения с другими бронями» — это проверка через несколько документов, и её пришлось бы городить вручную: либо распределённой транзакцией, либо optimistic-lock с ретраями. Для MVP — лишняя сложность ради записи, которую реляционка делает декларативно одной строкой DDL. Цена: если в будущем брони станут schema-less (произвольные поля под разные типы комнат), за гибкость придётся доплатить миграциями — но на MVP этого требования нет.

Шаг 5. Данные и жизненный цикл брони

Проектируем данные на трёх уровнях — от сущностей бизнеса до таблиц PostgreSQL: модель данных: три уровня, а конкретику по ключам, связям и ACID — в базы данных для аналитика (если бы MeetRoom строили на документной базе, моделировали бы иначе — под паттерн доступа, см. моделирование в NoSQL). На физическом уровне центральная таблица bookings в первом приближении такая:

ПолеТипНазначение
iduuid PKидентификатор брони
room_iduuid FK → roomsкакая комната
organizer_iduuid FK → usersкто забронировал (на нём держится «вижу только свои»)
time_rangetstzrangeпромежуток брони; на пару (room_id, time_range) висит ограничение от пересечений
statusenumdraft / confirmed / cancelled

Отдельно описываем, как живёт сама бронь. Три статуса и разрешённые переходы: черновик (draft)подтверждена (confirmed)отменена (cancelled). Что разрешено, а что нет: из draft можно в confirmed или сразу в cancelled; из confirmed — только в cancelled; из cancelled — никуда (терминальное состояние). И отдельно запрещаем отменять бронь, время которой уже прошло. Это диаграммы состояний — и именно запрещённые переходы (вернуть отменённую бронь в активную, отменить прошедшую) ловят класс багов, который иначе всплывёт в проде.

Шаг 6. Контракт: API, ошибки, доступ

Чтобы веб-приложение и внешние системы общались с MeetRoom, задаём REST API: GET /rooms, POST /bookings, DELETE /bookings/{id}. Ключевой эндпойнт целиком, чтобы было что унести:

POST /bookings  { "room_id": "...", "start": "2026-06-01T10:00:00Z", "end": "2026-06-01T11:00:00Z" }
  201 Created            — бронь создана, в теле id и status: "confirmed"
  409 Conflict           — слот уже занят (сработало ограничение из ADR-001)
  422 Unprocessable      — участников больше вместимости комнаты

Счастливый путь — это половина контракта; вторая половина — что вернётся при ошибке: 409 на занятый слот, 422 на превышение вместимости. Обратите внимание: 409 — это не баг, а штатный ответ, который фронт обязан показать пользователю человеческим текстом «слот заняли, пока вы выбирали». Это ошибки как часть контракта. Кто вошёл — решает аутентификация через OAuth2 (корпоративный SSO), а что кому можно — авторизация на уровне данных: NFR «сотрудник видит только свои брони» — это не фильтр в интерфейсе, а проверка на сервере, что строка принадлежит запрашивающему. Что из данных брони считать чувствительным (с кем встреча) — в записи про безопасность данных и PII.

Шаг 7. Интеграции: календарь по событию

MeetRoom не живёт один: создал бронь — событие должно улететь в корпоративный календарь. Делать это синхронно или асинхронно — развилка из записи синхрон, асинхрон, очереди; для уведомления календаря берём асинхронный путь — исходящий вебхук booking.created. Сам конверт события — тоже артефакт, который аналитик описывает в контракте:

POST {calendar_webhook_url}
{ "event_id": "evt_8f2a", "type": "booking.created",
  "booking_id": "b_1042", "room_id": "r_07",
  "start": "2026-06-01T10:00:00Z", "end": "2026-06-01T11:00:00Z" }
Поле event_id здесь не для красоты — это ключ идемпотентности: по нему календарь отличит повторную доставку от новой брони.

Сам сценарий «бэкенд создаёт бронь → шлёт событие календарю → тот подтверждает» удобнее всего нарисовать sequence-диаграммой — кто кого зовёт во времени. А поскольку событие может прийти дважды, обработчик на стороне календаря должен быть идемпотентным — про это идемпотентность (пример там на платеже, но для события booking.created механика ключа работает один в один).

flowchart TD
  A["Бизнес-боль:
хаос с переговорками"] --> B["Выявление
+ стейкхолдеры"] B --> C["SRS:
что строим"] C --> D["HLD/LLD + ADR:
как строим"] D --> E["Данные +
состояния брони"] E --> F["API + ошибки
+ авторизация"] F --> G["Интеграции:
календарь по вебхуку"] G --> H["Миграции +
эксплуатация"] H --> I["Метрики:
прижилось ли?"]

Схема показывает весь маршрут MeetRoom сверху вниз. Из бизнес-боли (хаос с переговорками) рождается выявление требований и карта стейкхолдеров; из них — SRS (что строим); из SRS — дизайн HLD/LLD с журналом решений ADR (как строим); дальше детализируются данные и жизненный цикл брони; затем — контракт API с ошибками и авторизацией; потом — интеграции с внешним календарём через вебхук; потом — миграции схемы и эксплуатация в проде; и в конце — метрики, которые отвечают, прижился ли сервис. Поток не строго водопадный: на практике он итеративный, и нижний шаг часто вскрывает дыру в верхнем (при проектировании API выясняется, что в SRS забыли requirement про отмену). Но порядок навыков именно такой — каждый следующий опирается на предыдущий. Тонкость: оглавление справочника учит темы в порядке «API → данные» (контракт проще для входа), а в проекте модель данных проектируют до контракта API — поэтому в маршруте шаг с данными идёт раньше. Это не противоречие: порядок обучения и порядок проектирования различаются намеренно.

Шаг 8. Эволюция и эксплуатация

MeetRoom выкатили — это не конец, а начало. Бизнес попросил хранить отдельно тему встречи и заметку вместо одного поля description — меняем схему работающей базы без даунтайма. Артефакт миграции — последовательность, а не один ALTER: (1) добавить нулёвые колонки title и note, (2) бэкфилл — старое description переложить в title пачками по 1000 строк, (3) переключить запись приложения на новые поля, (4) только потом удалить старую колонку. Каждый шаг обратим, на каждом сервис жив. Про это — миграции данных и бэкфилл. Сервис доезжает до пользователей через несколько окружений — CI/CD, крутится в контейнерах (Docker и K8s), быстро отдаёт сетку доступности за счёт кэширования. Чтобы понимать, что он жив и где тормозит, закладываем логи, метрики, трейсы; обещание доступности из SRS превращается в SLA/SLO, а один интегратор не должен уронить сервис всем — ставим rate limiting.

Время и часовые пояса — отдельный риск бронирования

MeetRoom — это сервис про слоты времени, и время здесь главный источник коварных багов. Правила, которые надо проговорить ещё в SRS, а не ловить в проде:

Хранить в UTC. В БД (поле time_range) и в API — всегда UTC с явным Z на конце: 2026-06-01T10:00:00Z. Никаких «локальных» времён в хранилище — иначе одну и ту же бронь два сервера в разных зонах поймут по-разному.

Показывать в зоне пользователя. Конвертация UTC → местное время — задача клиента (или слоя представления), на основе зоны браузера или профиля. Бэкенд не должен решать, в каком поясе рисовать сетку: офис в Москве и удалёнщик во Владивостоке видят один слот в своём времени, но это одна и та же запись в UTC.

Граница суток. «Сетка на сегодня» — это всегда «сегодня в зоне пользователя», а не в UTC. Иначе для Владивостока сутки в UTC закончатся в середине его рабочего дня, и часть утренних слотов уедет «на завтра». Границу суток считаем в локальной зоне, фильтруем по UTC.

Переход на летнее время. В зонах с DST (например, часть Европы) дважды в год сутки длятся 23 или 25 часов: одно локальное время может не существовать или встретиться дважды. Хранение в UTC снимает почти всю боль — UTC не прыгает; но на показе и при «повторить бронь на следующую неделю» проверяйте, что 14:00 по-прежнему 14:00 для пользователя, а не сдвинулось на час. Россия с 2014 года DST не применяет, но как только MeetRoom выйдет за её пределы — этот класс багов оживёт.

Шаг 9. Прижилось ли: метрики

Последний и часто забытый шаг: фичу выкатили — а она работает? Без цифр это вопрос веры. Для MeetRoom главная метрика — доля встреч, забронированных через сервис, а не «по памяти»; ставим цель в SLA-стиле: довести до 70% всех бронирований за два месяца (а через месяц мерим, идём ли к ней). Смотрим воронку и где отваливаются: открыл сетку (100%) → выбрал слот (60%) → подтвердил (45%) — если самый большой провал между «открыл» и «выбрал», значит больно не подтверждение, а поиск свободного слота: возможно, сетка грузится дольше тех самых 800 мс из NFR-02, и это уже гипотеза для A/B-теста. Всё это — в записи метрики, воронки, A/B. И когда копится словарь незнакомых терминов — держим открытым глоссарий.

Зачем смотреть на проект целиком

Каждый навык по отдельности — это инструмент в ящике. Но ценность аналитика не в том, что он знает, что такое SRS или sequence-диаграмма, а в том, что он умеет провести систему от размытой боли до работающего и измеримого продукта, не уронив ни один стык. Этот сквозной взгляд — то, что отличает человека, который «прошёл курс», от того, кто «сделал проект». Учите навыки по записям, но держите в голове весь маршрут MeetRoom: он показывает, как куски собираются в целое.

Как это спрашивают на собесе

Любимый формат сильного собеседования — не «что такое X», а «проведите меня по вашему проекту». Кандидата просят: «расскажите, как вы вели какую-нибудь систему от требований до прода» или «вот задача — спроектируйте сервис бронирования, рассуждайте вслух». Что проверяют: видите ли вы весь маршрут (а не только любимый кусок), не пропускаете ли выявление и метрики, помните ли про стыки — авторизацию, ошибки, идемпотентность, миграции. Слабый кандидат прыгает сразу в таблицы БД; сильный начинает с «а какую проблему решаем и кто стейкхолдеры» и доводит до «как поймём, что сервис прижился». Умение рассказать связный сквозной путь ценится выше, чем знание любого отдельного термина.

Частые вопросы

Это обязательный порядок шагов или можно иначе?

Порядок навыков — да, именно такой: каждый следующий шаг опирается на предыдущий (нельзя писать SRS, не выявив требования; нельзя проектировать API, не зная модель данных). Но сам процесс не строго водопадный, а итеративный: на практике вы постоянно возвращаетесь назад, потому что нижний уровень вскрывает дыру в верхнем — проектируя LLD, обнаруживаете, что в SRS забыли требование. Маршрут MeetRoom показывает логическую зависимость навыков, а не запрет ходить кругами.

Зачем нужен сквозной пример, если есть отдельные записи по каждой теме?

Отдельные записи учат навыкам — что такое SRS, как нарисовать sequence, чем RBAC отличается от ABAC. Но реальная работа аналитика — это не применение одного навыка, а проведение системы через все стыки так, чтобы ни один не рассыпался. Сквозной пример показывает, как один артефакт перетекает в другой (выявленное требование → строка SRS → блок HLD → таблица LLD → endpoint API) и почему порядок именно такой. Это превращает набор полочек в связный маршрут — то, что спрашивают на собесе и делают на проекте.

С чего начать, если я только учусь?

Идите по оглавлению справочника сверху вниз — он выстроен от фундамента к надстройке: контекст и роли → основы → требования → документы → процесс и продукт → API → интеграции → данные → эксплуатация → инструменты. А эту запись держите как карту: пройдя очередную тему, возвращайтесь сюда и смотрите, какое место навык занимает в маршруте MeetRoom. Так отдельные знания сразу укладываются в общую картину, а не повисают в воздухе.