Высокоуровневый дизайн и deep-dive
Сначала нарисуй высокоуровневый дизайн — клиент, балансировщик, сервис, данные — затем выбери один-два сложных компонента и копни глубоко. HLD показывает, что умеешь компоновать; deep-dive — что умеешь инженерить. Обоснуй каждую коробку, набросай API и модель данных первыми.
Кандидат рисует вычурную схему: двенадцать коробок, service mesh, три очереди сообщений, отдельный аналитический конвейер. Интервьюер задаёт один вопрос — «зачем очередь между API и базой?» — и кандидат замирает, потому что причины не было; очередь стояла, потому что у схемы «должны быть» очереди. Сравни с кандидатом, что рисует пять коробок, каждую из которых может защитить одним предложением, а затем говорит: «по-настоящему сложное тут — держать ленту свежей при 300K чтений/с, давайте остаток времени потрачу ровно на это». Второй нарисовал меньше, а показал больше. Широта — это ставка на входе; интервью выигрывают в глубине.
Две фазы, два разных проверяемых навыка
Большинство кандидатов воспринимают интервью как одно занятие: рисование. Но когда интервью разваливается, почти всегда причина в том, что кандидат потратил всё время на одну фазу и не добрался до другой.
После требований и оценки у дизайна две отдельные фазы, и они доказывают разные компетенции:
- Высокоуровневый дизайн (HLD) — простая сквозная картина того, как запрос течёт через систему: клиент → балансировщик → сервис(ы) → хранилище(а), с кэшем, очередью или CDN там, где оценка их оправдала. Это доказывает, что ты умеешь компоновать известные компоненты в работающее целое. Должно быть быстро и почти скучно — стандартный скелет, специализированный под задачу.
- Deep-dive — выбор одного-двух компонентов, что реально сложны для этой задачи, и их детальная инженерия. Это доказывает, что ты умеешь инженерить, не просто собирать. Здесь сеньоры отрываются от мидлов.
Ошибка — потратить всю сессию на первую фазу, добавляя всё больше коробок, делая HLD всё вычурнее, и никогда не дойти до второй. Корректный простой HLD плюс один deep-dive бьёт раскидистый HLD без глубины нигде. Интервьюер и так считает, что балансировщик ты нарисуешь; он ждёт увидеть, что ты сделаешь с частью, у которой нет стандартного ответа.
Скелет высокоуровневого дизайна
Зачем вообще нужен стандартный скелет? Он позволяет пройти HLD за две-три минуты — освобождая остаток сессии для deep-dive, где интервью реально выигрывается. Большинство систем делят скелет; твоя задача — специализировать его, не изобретать заново. Поток по умолчанию:
клиент → DNS/CDN → балансировщик → API/сервис-слой → слой данных
│
кэш · очередь (где оправдано)- Клиент → CDN/DNS: статика и гео-роутинг живут на краю (юнит трафика).
- Балансировщик: разносит запросы по stateless сервис-слою (юнит трафика). Он есть, потому что оценка сказала, что одна коробка не обслужит QPS.
- Сервис-слой: stateless app-серверы, масштабируются горизонтально (юнит масштабируемости). Stateless, чтобы любой узел обслуживал любой запрос.
- Слой данных: база(ы), что выбрали паттерны доступа (урок требований). Шардированная, если оценка записи это потребовала.
- Кэш / очередь / CDN: добавляются только когда число их оправдало — кэш, потому что чтений ≫ записей; очередь, потому что путь записи нужно сделать асинхронным; CDN, потому что полоса egress была велика.
Нарисуй это за пару минут, проговаривая, почему каждая коробка тут, в терминах требования или оценки. Проговаривание — это суть: коробка без обоснования — обуза, не актив.
▸Почему это работает
Зачем держать HLD намеренно простым, даже разреженным? Потому что каждая коробка — заявление, что придётся защищать, и необоснованная коробка — быстрейший способ потерять доверие. Работа интервьюера — зондировать: «зачем это тут?», «что если оно упадёт?», «сколько это стоит?». Очередь, добавленная для красоты, становится ловушкой в момент, когда спросят, что она даёт. Хуже того, лишние компоненты раздувают поверхность отказа — больше того, что падает, больше границ согласованности для рассуждения — это провал переинженеринга из урока требований, ставший зримым. Начни с минимального скелета, что вытягивает требования, и добавляй компонент, только когда можешь назвать конкретное число или режим отказа, что его требует. Простота — не недостаток искушённости; это сеньорский сигнал, что ты добавляешь сложность лишь там, где она окупается.
Набросай API и модель данных
До или рядом с HLD набросай два артефакта, что заземляют дизайн в чём-то конкретном:
API. Горстка эндпоинтов, реализующих функциональные требования — глаголы из урока требований, превращённые в вызовы. Для сокращателя ссылок:
POST /links {url} → {shortCode}
GET /{shortCode} → 302 редирект на url
GET /links/{shortCode}/stats → {clicks, ...}API заставляет встретиться лицом к лицу с разбиением чтение/запись, идемпотентностью и формой ответа — и даёт интервьюеру конкретный контракт, на который давить.
Модель данных. Ключевые сущности (из требований) как таблицы/коллекции с ключами и — главное — ключом партиции/шарда, если шардишь (юнит распределения данных). Ключ шарда — решение по данным с наибольшим рычагом: выбери его под доминирующий паттерн доступа, чтобы частый запрос бил в один шард, и чтобы разнести нагрузку, чтобы ни один шард не был горячим.
links: short_code (PK) url created_at owner_id — шард по short_code (точечные lookup)
clicks: short_code ts ... (append-heavy, time-series) — шард по short_code, по бакетам времениЭти два наброска превращают махающую руками схему коробок в дизайн с реальным контрактом и реальной схемой — и вскрывают сложные части (плохой ключ шарда, отсутствующий индекс, болтливый API) до deep-dive.
Выбор deep-dive: где живёт сложность
Deep-dive — сердце интервью, и выбор того, во что копать, сам по себе сеньорский навык. Выбери компонент, где задача реально сложна — обычно тот, что пометила оценка, или тот, что паттерны доступа сделали неудобным:
- Горячий путь чтения при 300K чтений/с → копни в кэш и стратегию fan-out (юнит кэширования).
- Темп записи за пределом одной primary → копни в схему шардинга и ключ шарда (юнит распределения данных).
- Требование строгой согласованности на распределённой записи → копни в репликацию и обмен CAP/PACELC.
- Fan-out вроде ленты знаменитости → копни в решение fan-out-on-write против fan-out-on-read и гибрид.
Затем иди глубоко: структура данных, режимы отказа, краевые случаи, числа. Deep-dive — где ты показываешь, что реально строил системы: обсуждаешь проблему горячего ключа, thundering herd (шторм одновременных перестроек кэша после истечения TTL) на промахе кэша, стоимость ребаланса при сплите шарда. Объяви выбор вслух («интересная часть — X, я сосредоточусь там»), чтобы интервьюер мог перенаправить, если хотел другой компонент — и чтобы он знал, что ты отличаешь сложную часть от лёгкой.
▸Частая ошибка
Ошибка deep-dive — идти вширь вместо вглубь — тронуть десять компонентов по тридцать секунд каждый вместо одного компонента на десять минут. Кажется безопаснее (покрываешь больше), но читается как поверхностность: ты ни разу не показал, что можешь хоть что-то проинженерить, только что умеешь называть. Тот же инстинкт рождает скороговорку под конец «и добавим мониторинг, и CI-конвейер, и rate limiting, и…» — правдиво, но обобщённо, и видно, когда сказать про саму задачу больше нечего. Лечение: выбери сложный компонент и копай глубже, пока интервьюер не остановит. Глубина по верному компоненту — сильнейший сигнал, что ты можешь послать; тур по баззвордам — слабейший.
Ты нарисовал чистый HLD из пяти коробок, осталось 30 минут. Как с наибольшей ценностью потратить остаток?
Интервьюер спрашивает: «зачем очередь сообщений между твоим API и базой?» Как выглядит сильный ответ?
Высокоуровневый дизайн доказывает, что ты умеешь _______ известные компоненты в работающее целое, тогда как deep-dive доказывает, что ты умеешь проинженерить один-два по-настоящему сложных части — и интервью выигрывают во втором, ведь широта предполагается, а глубина — то, что различает.
- 01Что доказывает высокоуровневый дизайн и каков его скелет?
- 02Зачем набрасывать API и модель данных и каково решение по данным с наибольшим рычагом?
- 03Как выбрать deep-dive и каков режим провала?
После требований и оценки дизайн делится на две фазы, проверяющие разное. Высокоуровневый дизайн доказывает, что ты умеешь компоновать: нарисуй простой сквозной скелет — клиент → DNS/CDN → балансировщик → stateless сервис-слой → слой данных, с кэшем, очередью или CDN, добавленными только где число или режим отказа их оправдал — и проговори, зачем каждая коробка, ведь необоснованная коробка — обуза, а лишние раздувают поверхность отказа. Заземли двумя набросками: API (функциональные глаголы как эндпоинты, обнажающие разбиение чтение/запись и идемпотентность) и моделью данных (ключевые сущности как таблицы с ключами и важнейшим ключом шарда, выбранным под доминирующий паттерн доступа и разнос нагрузки). Затем приходит часть, что выигрывает интервью: deep-dive. Выбери один-два реально сложных компонента — горячий путь чтения, схему шардинга, строго-согласованную запись, fan-out знаменитости — объяви выбор и иди глубоко по структурам данных, режимам отказа, горячим ключам и числам. Широта — ставка на входе; глубина — то, что различает — корректный простой HLD плюс один реальный deep-dive бьёт раскидистую схему без глубины нигде, а тур по баззвордам под конец — слабейший сигнал, что ты можешь послать. Теперь, когда заканчиваешь рисовать HLD, спроси: какая одна коробка тут реально сложна? Копай ровно в неё — и не останавливайся, пока не остановит интервьюер.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.