HLD (High-Level Design) и LLD (Low-Level Design) — это два уровня дизайн-документа, отвечающего на вопрос «как построить систему». HLD — архитектура крупными блоками: какие компоненты, как они связаны, как течёт поток данных; примерно уровни Context и Container из C4. LLD — детали: схемы таблиц, контракты API, алгоритмы, обработка ошибок. HLD обычно пишет аналитик или архитектор, LLD — разработчик. В потоке создания системы это звено между требованиями и кодом: SRS говорит «что», HLD/LLD — «как», ADR — «почему именно так». Не каждой задаче нужны оба: на маленькую фичу хватит абзаца, на платёжную систему — обоих.
Однажды разработчик ушёл в отпуск на середине большой фичи, и его кусок достался другому. Передавать было нечего: вся «архитектура» жила в голове первого. Второй потратил три дня, чтобы просто понять, как задумано — где какие сервисы, какая схема данных, кто кого вызывает. А ведь это ровно те три дня, которые сэкономила бы одностраничная HLD, нарисованная в начале. С тех пор я отношусь к дизайн-документу не как к формальности «для архива», а как к карте, без которой команда блуждает.
Зачем разделять «что» и «как»
Между требованием и кодом есть пропасть. Требование говорит «пользователь бронирует переговорку, двойное бронирование недопустимо». Код — это сотни строк на конкретном языке. Прыгнуть из одного в другое за один шаг можно на маленькой задаче, но на большой между ними нужен мост — дизайн. Дизайн отвечает на вопрос «как мы выполним это требование»: какие будут компоненты, какая схема данных, как именно гарантируем, что два человека не займут один слот.
Разделение на «что» и «как» — это не бюрократия, а разделение ответственности. Требования (SRS) принадлежат бизнесу и аналитику: их можно обсуждать с заказчиком. Дизайн (HLD/LLD) принадлежит инженерам: заказчику неинтересно, какая у вас схема таблиц, ему важно, что бронь работает. Смешав их, вы получаете документ, который непонятен ни бизнесу, ни разработке.
Три документа отвечают на три вопроса
SRS — что система делает (требования). HLD/LLD — как она это делает (устройство). ADR — почему устроена именно так (обоснование выбора). Это три разных вопроса, и попытка ответить на все в одном документе обычно проваливает каждый. Держите их раздельно и связывайте ссылками.
HLD — высокоуровневый дизайн
HLD отвечает на вопрос «из чего система состоит и как части взаимодействуют» — но на уровне крупных блоков, без деталей реализации. Это вид с высоты птичьего полёта. Если вы знакомы с нотацией C4, то HLD — это примерно уровни Context и Container: система целиком в окружении и её крупные части (веб-приложение, бэкенд, база, очередь).
Что внутри HLD: контекст (где система живёт, с кем общается), компоненты и их зона ответственности, потоки данных в основных сценариях, ключевые технологии (на уровне «база, очередь, протокол», но не «индекс по полю X»), и нефункциональные решения (как закрываются NFR: масштабирование, отказоустойчивость, кэш). HLD читают многие: аналитик, разработчики, тестировщики, иногда заказчик — поэтому он не тонет в деталях.
HLD: Сервис бронирования переговорок «MeetRoom» (фрагмент)
КОМПОНЕНТЫ
- Web SPA — интерфейс сотрудника в браузере
- Booking API — бэкенд: бизнес-логика броней, валидация
- PostgreSQL — хранилище комнат, броней, пользователей
- SSO (внешн.) — аутентификация через OpenID Connect
- Calendar (внешн.) — принимает события о бронях по вебхуку
ОСНОВНОЙ ПОТОК (создание брони)
1. Web SPA -> Booking API: POST /bookings (после входа через SSO)
2. Booking API проверяет в PostgreSQL, что слот свободен
3. Booking API создаёт бронь в транзакции (защита от двойной)
4. Booking API -> Calendar: вебхук booking.created
5. Booking API -> Web SPA: 201 Created с данными брони
КЛЮЧЕВЫЕ РЕШЕНИЯ
- Хранилище: PostgreSQL (атомарность брони) — см. ADR-007
- Защита от двойного бронирования: уникальный constraint
на (room_id, slot) в БД, не только проверка в коде
Заметьте: HLD называет компоненты и поток, но не лезет в имена полей и тела запросов. Это уровень «какие коробки и стрелки». А почему PostgreSQL — не объясняется здесь, стоит ссылка на ADR. Каждый документ занимается своим.
LLD — низкоуровневый дизайн
LLD спускается внутрь компонента и отвечает на вопрос «как именно это реализовано». Здесь живут схемы таблиц с типами полей, точные контракты API с телами запросов и ответов, алгоритмы, обработка краевых случаев и ошибок. LLD читает в основном тот, кто будет писать код, поэтому он плотный и технический.
LLD: Booking API — создание брони (фрагмент)
ТАБЛИЦА bookings
id uuid PRIMARY KEY
room_id uuid NOT NULL REFERENCES rooms(id)
user_id uuid NOT NULL REFERENCES users(id)
slot_start timestamptz NOT NULL
slot_end timestamptz NOT NULL
topic text NOT NULL
created_at timestamptz NOT NULL DEFAULT now()
UNIQUE (room_id, slot_start) -- защита от двойной брони
КОНТРАКТ POST /bookings
Запрос (application/json):
{ "roomId": "uuid", "slotStart": "2026-05-24T10:00:00Z",
"slotEnd": "2026-05-24T10:30:00Z", "topic": "Синк",
"participants": 4 }
Ответы:
201 Created — бронь создана, тело: объект booking
409 Conflict — слот занят, тело: { "error": "SLOT_TAKEN",
"suggestions": [ ...ближайшие свободные слоты ] }
422 Unprocessable — participants больше вместимости комнаты
401 Unauthorized — нет валидной сессии SSO
АЛГОРИТМ
1. Проверить вместимость: participants <= room.capacity, иначе 422
2. INSERT в bookings внутри транзакции
3. Нарушение UNIQUE (room_id, slot_start) -> откат -> 409 SLOT_TAKEN
4. Сформировать suggestions: 3 ближайших свободных слота комнаты
5. Отправить вебхук booking.created (асинхронно, вне транзакции)
Разница с HLD теперь видна на ощупь. HLD говорил «защита от двойного бронирования через constraint» — а LLD показывает какой именно constraint (UNIQUE на room_id + slot_start) и что при его нарушении вернётся 409 с конкретным телом. HLD — это карта города, LLD — это план одного здания с розетками. И LLD для контракта смыкается с тем, что мы знаем про REST API — коды ответов, тела, ошибки — это и есть язык LLD на уровне интерфейсов.
HLD против LLD: таблица
| Параметр | HLD | LLD |
|---|---|---|
| Уровень | Система и крупные блоки | Внутренности одного компонента |
| Вопрос | Из чего состоит, как связано | Как именно реализовано |
| Содержимое | Компоненты, потоки, ключевые технологии | Схемы таблиц, контракты, алгоритмы |
| Кто пишет | Аналитик / архитектор | Разработчик |
| Кто читает | Все: бизнес, аналитик, разработка, QA | В основном разработчик |
| Аналог в C4 | Context + Container | Component + Code |
Где HLD и LLD в потоке от требований к коду
flowchart LR A["Бизнес-потребность"] --> B["SRS: что строим"] B --> C["HLD: как в целом"] C --> D["LLD: как в деталях"] D --> E["Код"] C -.почему так.-> F["ADR"] D -.почему так.-> F
Схема показывает поток слева направо. Из бизнес-потребности рождается SRS — что система должна делать. Из SRS вырастает HLD — как она устроена крупными блоками. Из HLD детализируется LLD — таблицы, контракты, алгоритмы. И уже из LLD пишется код. Сбоку стоит ADR: и HLD, и LLD ссылаются на него там, где на развилке был сделан неочевидный выбор — ADR объясняет «почему», не повторяя «как». Поток не строго водопадный: на практике он итеративный, и нижний уровень нередко вскрывает дыру в верхнем (при написании LLD выясняется, что в HLD забыли компонент).
Не каждой задаче нужны оба документа
HLD и LLD — это уровни детализации, а не обязательный ритуал. На правку текста кнопки не нужен никакой дизайн-документ. На новую фичу средней руки хватит лёгкого HLD на полстраницы. Полноценные HLD + LLD оправданы там, где система сложная, команда большая или цена ошибки высока. Правило то же, что и со спецификацией: ровно столько формальности, сколько снимает реальные риски.
Откуда это взялось
Разделение на high-level и low-level design пришло из водопадной модели и классической программной инженерии 1970–80-х, где жизненный цикл делили на жёсткие фазы: требования → проектирование → кодирование → тестирование. Фаза проектирования сама делилась на «архитектурный дизайн» (общая структура) и «детальный дизайн» (внутренности модулей) — это и есть предки HLD и LLD. Agile в 2000-х размыл границы: дизайн стал лёгким, итеративным, иногда сводится к диаграмме на доске. Но сами уровни никуда не делись — «нарисуй архитектуру крупными блоками, потом детализируй» остаётся базовым инженерным движением.
Как это спрашивают на собесе
«Чем HLD отличается от LLD?» — проверяют, понимаете ли уровни детализации (система vs внутренности компонента) и кто что пишет. «Что входит в HLD?» — ждут компоненты, потоки данных, ключевые технологии, а не схемы таблиц (это уже LLD). «Где в дизайн-документе место для выбора технологии и его обоснования?» — здесь хорошо вспомнить связку с ADR: само решение отражается в HLD, а его обоснование — в отдельном ADR.
Частые вопросы
HLD пишет аналитик или разработчик?
Чаще аналитик или архитектор — потому что HLD ближе к требованиям и его читают все, включая бизнес. Аналитик хорошо видит компоненты и потоки данных, потому что только что описал их в требованиях. LLD почти всегда пишет разработчик: схемы таблиц, контракты и алгоритмы — это его зона. На практике HLD нередко рождается в паре аналитик + тимлид: первый отвечает за «что и в каких границах», второй — за технические решения.
Нужны ли HLD и LLD в Agile?
В лёгком виде — да, в тяжёлом водопадном — почти никогда. Agile не отменяет дизайн, он делает его лёгким и итеративным: HLD может быть диаграммой на полстраницы, LLD — комментарием в задаче или наброском контракта. Полные подписанные документы оправданы только там, где сложность и цена ошибки этого требуют. Главное не путать «нет толстого документа» с «нет дизайна» — спроектировать перед кодом всё равно нужно.
Чем HLD отличается от SRS?
SRS отвечает на «что система делает» (требования), HLD — на «как она устроена» (дизайн). SRS принадлежит бизнесу и обсуждается с заказчиком, HLD принадлежит инженерам. Пример: SRS говорит «двойное бронирование недопустимо» — это требование; HLD говорит «защищаемся уникальным ограничением в БД» — это уже способ его выполнить. Они идут друг за другом в потоке: сначала SRS, потом по нему HLD.