---
title: Конспект материала 23 — «Интервью по System Design» (Поломодов, Tinkoff): запись реального интервью
source_video: https://www.youtube.com/watch?v=Wh5Ya6UFG1k
author: интервьюер — Александр Поломодов (Tinkoff, архитектура мобильного банка, курирует SDI); кандидат — Даниил, коллега Поломодова (архитектор направления авторизации, сам проводит дизайн-интервью)
конспект: подготовлено 2026-09-17, TASK-45.27; ArchDays 2022, 1:26:41; по автотранскрипту (имена/термины восстановлены по контексту: «позглись» = Postgres, «ткань месяц Q» = Kafka, «лот-бокс» = outbox и т.п.); запись начинается сразу с уточнения функциональных требований — интро обрезано
статус: единственная на русском запись, где **интервьюер уровня Т-сети проводит секцию вживую и потом сам разбирает её по шагам**; задача — бронирование отелей, та же, что приводится как пример в гайде автора (материал 16); тайминг ~60 мин интервью + 26 мин разбор и Q&A зала
---

# Материал 23: Интервью по System Design — Поломодов × Даниил (запись реальной секции)

Живая секция на флипчарте с конференции ArchDays 2022: Поломодов (интервьюер) даёт кандидату задачу «система бронирования отелей», час проектирования, затем развёрнутый фидбэк и Q&A зала. Это видеоверсия того самого формата Tinkoff, который автор описал в докладе «Как подготовиться и пройти System Design Interview» (материал 16) — и даже задача та же («бронирование номеров в отеле» как пример дня доклада). Для нас это эталон «как выглядит сильное исполнение от первой минуты до вердикта»: кандидат проходит срезы (методичность, границы, контракты), на которых в моках karpov.courses (материал 22) люди сыпались, и получает разбор двух настоящих пробелов — обе про оценку объёмов данных.

---

## 1. Формат и участники

- **Хронометраж:** ~60 мин интервью (запись стартует уже с функциональных требований) → разбор интервьюера ~8 мин → Q&A зала ~18 мин.
- Задача: система бронирования отелей (гость бронирует номер; менеджеры управляют отелями/номерами; оплата — внешний провайдер). Поиск/фильтры/карты, регистрация отелей, аналитика — осознанно вынесены за скобки.
- Кандидат — не студент: архитектор авторизации в Tinkoff, сам водит дизайн-интервью, «готовился и переживал». Это калибрует планку: Strong-исполнение показал человек, который сидит по другую сторону доски.
- Задача в банке Tinkoff новая — «давал всего несколько раз»; останется учебной.

## 2. Ход секции (по таймкодам)

**[00:00–12:00] Границы + функциональные требования.** Кандидат объявляет подход («мне нравится C4, начнём с границ системы») и рисует участников: гость, менеджеры, внешний платёжный провайдер. Скоуп-вопросы решаются на лету: юзер-профайлинг/чат — «есть, но не наша система»; регистрация отелей — «вернёмся, если останется время» (интервьюер: админ-панель он сам убрал из базового скоупа). Функциональные требования сразу фиксирует **REST-контрактами**: `GET /hotels`, `GET /hotels/{id}/roomtypes/{id}`, `POST /reservations` (payload: userId, startDate/endDate, roomTypeId, hotelId, количество номеров — «5 одноместных для коллег одним бронированием»), `DELETE` (оговорка: в реальности soft delete), `PATCH`, отдельный `POST` оплаты. Ключевая доменная находка: бронируется **roomType, а не комната** — «сколько я пользуюсь букингами — это всё-таки roomType»; вложенные ресурсы «как в REST-спецификации».

**[12:12–17:55] NFR + оценка нагрузки.** Интервьюер даёт вводные: 20 000 отелей в РФ, номерной фонд ~1 млн (статистика 2021), заполнение 60%, среднее пребывание 3 дня, воронка «100% смотрят отель → 10% играют с датами → 1% бронирует». Расчёт кандидата: 1M × 0.6 / 3 дня = **200K броней/день** → среднее ~2 rps записи («наши любимые константы» — 86 400), с праздничными всплесками закладываем ~50 rps. Просмотры: 200K × 100 (воронка) = 20M/день → **в пиках ~5K rps чтения**. Вывод-водораздел: чтение на 2–3 порядка тяжелее записи → кэш и реплики.

**[17:55–29:00] Контейнерная диаграмма.** API Gateway (auth + балансировка: «банальный nginx round-robin»), **Hotel & Room API + Booking API как два сервиса** («точно сервисная архитектура, не говорю про микросервисную»), перед Hotel API — кэш (5000 rps), БД master + слейвы на чтение с синхронизацией. Выбор хранилища: отели/комнаты — «реляционная не обязательна, но Postgres с констрейнтами проще», booking — **обязательно транзакционная целостность → реляционная** (про распределённые с транзакциями — Spanner/CockroachDB — вспомнил, но честно: не работал, «в наших реалиях» Postgres). Оплата — внешний провайдер; взаимодействие с ним через **outbox** (в транскрипте «лот-бокс»): локальная таблица попыток со статусом pending, retry до подтверждения.

**[29:04–39:00] Overbooking + доменная модель.** Кандидат сам ловит потерянное требование: «я забыл очень важный функциональный requirement — overbooking». Модель: `Reservation` (userId, roomTypeId, даты, цена, статус: pending → оплачен / отменён), `RoomType` (base price, total count, **overbooking-мультипликатор**: для стандартных комнат больше, для пентхаусов меньше — «цена ошибки: переселять в более дорогое жильё»), `Room` (конкретный номер со статусами клининг/ремонт — для ресепшена). Динамическое ценообразование (вопрос интервьюера «как в авиакомпаниях») — множитель от заполнения, «делать полноценную систему — отдельная задача, есть внешний сервис». Синхронизация справочника в booking-сервис: менеджмент пишет в БД + событие в **Kafka** → RoomType Sync Job обновляет локальную копию (денормализация, чтобы не ходить в чужой сервис).

**[39:00–49:50] Конкуренция за бронь (ядро задачи).** ACID и уровни изоляции: грязное/неповторяющееся чтение, фантомы, serializable («самый крутой режим, но при пиках база начнёт тормозить») → выбор **Repeatable Read**. Сценарий брони: `SELECT` свободных roomType'ов по диапазону дат → `INSERT` reservation + `UPDATE` счётчика — **в одной транзакции**; при конфликте (другая транзакция закоммитилась раньше) — ошибка сериализации → rollback → retry со свежими данными (число ретраев — в конфиге). Классифицирует выбор как **оптимистичные блокировки** (нет «супер-конкуренции» на одну запись; пессимистичные — `SELECT FOR UPDATE` — блокируют всех). В диалоге всплывает производственная история (автор по транскрипту неочевиден): в MySQL при некоторых уровнях изоляции Repeatable Read работает «не так с журналом» — на одном продукте пришлось делать блокировки на стороне приложения и строить реплицированную систему.

**[49:50–55:25] Шардирование.** «Если пойдём захватывать рынок и нагрузка вырастет на 1–2 порядка»: распределённые БД со строгой консистентностью (Spanner — «проприетарный, везде strict serializability»; CockroachDB — «слышал, не трогал»; YDB — «не ресёрчил, ничего не скажу» — честность границы знаний). Классика: **консистентное хеширование** — кольцо, **виртуальные шарды** (3 шарда × 10 = 30 точек), добавление ноды перекладывает данные «по часовой стрелке». Ключ шарда — **hotelId**: даты не подходят (стыки годов/месяцев — тормоза на выборках), «гиганты типа Radisson не страшно» — отелей тысячи, перекос терпим.

**[55:25–60:10] Финальный вопрос — идемпотентность.** Интервьюер из личного кейса (дважды купленные билеты в Сочи: ответ не дошёл → повтор → двойная покупка): как защититься? Решение в диалоге: **клиент генерит idempotency key (UUID v4, коллизий нет)**, состояние формы не сбрасывается до ответа; «в мобильном банке у нас это из коробки».

## 3. Вопросы интервьюера (полный каталог по назначению)

| Тип | Вопрос | Момент |
|---|---|---|
| скоуп-срез | «юзер-профайлинг, чат — включаем в нашу модель?» | 01:38 |
| скоуп-срез | «процедура регистрации отеля — учитываем?» | 05:13 |
| скоуп-срез | «нужна ли менеджерам аналитика (отказы, no-show)?» | 11:05 |
| оценка | «сколько отелей — Россия, регион, мир?» | 12:32 |
| оценка | «есть понимание RPS или прикинем?» | 13:17 |
| углубление | «динамическое ценообразование как в авиакомпаниях?» | 30:44 |
| углубление | «оплату — сразу в одной транзакции или статус pending?» | 41:08 |
| углубление | «как мы получаем свободные комнаты для страницы выбора дат?» | 41:30 |
| углубление | «какой уровень изоляции? сколько ретраев?» | 46:43 |
| масштаб | «нагрузка вырастет сильно — что тогда?» | 49:50 |
| форс-мажор | «запрос дошёл, ответ пользователю не пришёл → повтор → двойная покупка. Что делаем?» | 55:27 |

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

## 4. Сильные ходы кандидата (из фидбэка интервьюера)

1. **Методичность и пошаговость** — главная похвала: «очень системно, очень качественно… переход от шага к шагу». Не домен, не технологии — дисциплина хода.
2. **Границы и контракты сразу**: зафиксировал игроков, затем немедленно REST-контракты — «очистил то, что входит в систему»; каждый раз уточнял, входит ли кусок в скоуп → «не взял на себя больше работы, чем требуется» (у других кандидатов бывает «слишком расширяют»).
3. **Правильная глубина на второстепенном**: отели/комнаты прошёл быстро (действительно простая часть), сконцентрировался на букинге — «основной сложности».
4. **Сам поднял два из трёх «запасных» вопросов интервьюера**: overbooking вспомнил сам; динамическое ценообразование назвал и объяснил сам. «Даниил хлеб забрал — часть вопросов просто сам сказал в ходе проектирования».
5. **Честность границ знаний**: Spanner/CockroachDB/YDB — «не работал, не ресёрчил, ничего не скажу»; это не минус, а нормальная подача.
6. **Останавливаться на нужном уровне**: динамическое ценообразование — объяснил суть и явно сказал «полноценная система — отдельная задача».

## 5. Слабые места и пробелы (из фидбэка + наблюдения)

1. **Объёмы данных не посчитаны** — «не сильно закинули в объёмы»: сколько строк букингов за N лет; в timeline-схеме (roomType × дата) записей «достаточно много и они часто меняются и запрашиваются». Наш пересчёт для чувствительности: 20K отелей × ~5 типов × 365 дней ≈ **36M строк/год** — число, которое меняет тон разговора о шардах.
2. **Затык в доменной модели на датах**: написал таблицы, но «потерял часть, связанную с датами» — как выбирать доступность на конкретную дату. Интервьюер: «когда думают про сложность букинга, думают про то, как сложно забукать; а какие комнаты доступны — как будто уже знаем». Лечится вопросом самому себе: **«как я найду свободные комнаты?»** — ответ сам вытащил бы timeline-таблицу.
3. Наблюдения наши (в фидбэке не прозвучали): NFR не проговаривались как явная приоритизация (consistency > availability для брони прошло по умолчанию); latency-требований не было вовсе; единицы масштабирования («сколько держит одна нода API») не оценивались.

## 6. Техническое ядро (вынести в KB-практику)

- **Timeline-схема доступности**: строка на пару (roomType, дата); бронь на 3 дня = чтение/апдейт 3 строк. `SELECT … WHERE date BETWEEN start AND end` → `INSERT` reservation + `UPDATE` booked-счётчика в одной транзакции.
- **Оптимистичные vs пессимистичные блокировки**: выбор через оценку конкуренции на запись; ретраи после ошибки сериализации, лимит — конфиг.
- **Шардирование по hotelId** + консистентное хеширование с виртуальными шардами (×10 точек) — типовая пара для «справочник + факты» в бронировании.
- **Идемпотентность через клиентский UUID v4** — прямой ответ на «двойное списание»; у Tinkoff в мобильном банке — из коробки.
- **Картинки отелей — из CDN/S3** (замечание интервьюера в фидбэке): «частая отдача картинок» — хранить ссылки, раздавать из гео-распределённой сети, «но не критично для таких интервью».
- **Outbox для внешнего провайдера оплаты**: локальная таблица попыток (pending), retry, статус.

## 7. Q&A зала (что ещё сказал интервьюер о формате)

- **Sequence-диаграммы на интервью не рисуют** — «не хватает времени»; достаточно текстового порядка вызовов на компонентной диаграмме (ответ на претензию «разбирали БД без Flow»).
- **Последние ~5 минут — вопросы кандидата** интервьюеру: «несправедливо, когда час задаёшь вопросы ты».
- У каждой задачи — 3–6 запасных вопросов; здесь: идемпотентность (задан), динамическое ценообразование (закрыт самим кандидатом), окно оплаты 10–15 мин (успели по ходу).
- **Изменение требований по ходу — инструмент интервьюера**: «если кандидат слишком хорошо решает — подкидываем вырезанную сложность» и смотрим, как модифицирует систему. Плюс trouble-shooting: «что будет, если база упадёт, а событие в очередь уйдёт?»
- В запросах SQL расписывать всё не нужно — «достаточно, чтобы понял, о чём речь» (экономия времени).
- **Вердикт**: «по совокупности — выбил [ уровень senior ] по нашей внутренней градации»; оговорка: методичность связана с тем, что кандидат сам проводит SDI. Задача остаётся в банке.

## 8. Перенос на нашу подготовку (слоты 21–22.09)

- **Смотреть целиком перед слотом 22.09** (в индексе — P2, 60 мин): это единственное видео, где виден полный проход *сильного* кандидата по русскоязычной секции + разбор. Оптимально — после `lsd-karpov-mocks.md` (контраст «тонущих» и «сильного»).
- Скрипт первых 10 минут подтверждён образцово: C4-границы → участники → REST-контракты → NFR/числа. Ровно наш `methodology.md` §2–3 — расхождений нет, есть подтверждение.
- Три личные прививки от пробелов кандидата: (1) **посчитать объём хранения/строк** сразу после RPS — «сколько записей в год»; (2) в доменной модели спросить себя **«как я найду свободные X по датам?»** до рисования таблиц; (3) проговорить приоритет NFR одним предложением (consistency для денег/броней).
- Отработка вопросов из §3 — готовые реплики: «это входит в нашу систему или есть из коробки?», «есть понимание RPS или прикину?» (последний — сам кандидат, §2).
- Связанные материалы: `lsd-polomodov-guide.md` (М16 — тот же автор, тот же домен отеля: фреймворк 7 этапов в теории), `lsd-karpov-mocks.md` (М22 — контраст уровня), `../methodology.md` §2–3 (каркас совпадает), `../knowledge-base.md` §1 (числа: 86 400, воронка 100/10/1), `../classic-designs.md` §2 (лента — та же механика «строка на дату/юзера»).
