Job 2026 md

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 endINSERT 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 (лента — та же механика «строка на дату/юзера»).