коротко

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: таблица

ПараметрHLDLLD
УровеньСистема и крупные блокиВнутренности одного компонента
ВопросИз чего состоит, как связаноКак именно реализовано
СодержимоеКомпоненты, потоки, ключевые технологииСхемы таблиц, контракты, алгоритмы
Кто пишетАналитик / архитекторРазработчик
Кто читаетВсе: бизнес, аналитик, разработка, QAВ основном разработчик
Аналог в C4Context + ContainerComponent + 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.