Назначение
System Design Doc продумывает и согласовывает дизайн системы/фичи ДО кода. Цель — поймать ошибки на бумаге, где менять дёшево, а не в проде, где дорого. Это рабочий документ для обсуждения, а не формальность: его читают и критикуют до старта разработки. Тесно связан с C4 (диаграммы) и ADR (фиксация ключевых развилок).
Подробный шаблон
# System Design: <система / фича>
## Задача и цели
Что строим, зачем, метрики успеха. Что НЕ строим (не-цели).
## Требования
Функциональные: ключевые сценарии.
Нефункциональные (NFR): нагрузка (RPS), latency, доступность, объём данных, безопасность.
## Рассматриваемые варианты (reuse-first)
Подходы A/B/C с плюсами/минусами. Можно ли взять готовое?
## Выбранный дизайн
Компоненты (см. C4 Container), потоки данных, контракты API, модель данных.
## Масштаб и отказоустойчивость
Узкие места, поведение под нагрузкой, деградация, бэкапы/восстановление.
## Риски и открытые вопросы
Что неясно, что может пойти не так, что решаем позже.
Пример 1 — фрагмент (синхронизация ядра)
# System Design: Облачная синхронизация персонального ядра
## Задача и цели
Переносить избранное/заметки между устройствами. Успех: правка на устройстве A видна на B < 2 сек; 0 потерь данных при конфликте. Не-цели: шаринг между пользователями.
## Требования
Функц.: вход, push/pull ядра, realtime-обновление, офлайн→онлайн досинхрон.
NFR: до ~5k активных, latency синка < 2с, доступность 99.9%, изоляция данных между аккаунтами, объём ядра до ~5 МБ/юзер.
## Рассматриваемые варианты
- A — «последняя запись побеждает»: просто, но теряет данные при конфликте. ❌
- B — CRDT (Yjs): сходимость без потерь, сложнее. ✅
- C — ручной merge с UI разрешения: гибко, но трение для юзера. ⚠️
## Выбранный дизайн
B (CRDT/Yjs). Web App ↔ Sync API по WebSocket (realtime) + REST (bootstrap). Состояние ядра — Yjs-документ, персист в PostgreSQL, presence/pubsub через Redis. (см. C4 Container)
## Масштаб и отказоустойчивость
Узкое место — WS-соединения: Redis-адаптер для горизонтального масштабирования. Деградация: офлайн-режим на IndexedDB, досинхрон при возврате сети. Бэкап ядра — ежедневный дамп PG.
## Риски и открытые вопросы
Риск роста размера Yjs-истории → компакция. Открыто: лимит версий на хранение.
Пример 2 — фрагмент (автонарезка)
# System Design: Автонарезка видео в Shorts
## Задача и цели
Из длинного видео получать ≥3 клипа 9:16 с субтитрами. Успех: 12-мин видео → клипы < 60с обработки.
## Требования
NFR: видео до 1 ГБ, обработка асинхронная (не блокирует UI), устойчивость к сбою стороннего сервиса распознавания.
## Рассматриваемые варианты
- A — синхронно в запросе: просто, но таймауты на длинных видео. ❌
- B — фоновая очередь задач + статус: устойчиво, нужен воркер. ✅
## Выбранный дизайн
B. Загрузка → задача в очередь (Redis) → воркер: нарезка (ffmpeg) + субтитры (внешний STT) → клипы в хранилище → статус через WS. При сбое STT — ретрай, исходник не удаляется.
## Риски
Стоимость STT на объёме; деградация при недоступности — клипы без субтитров как fallback (открытый вопрос).
Чек-лист качества
- Есть цели И не-цели, метрики успеха.
- Нефункциональные требования заданы числами (RPS, latency, объём).
- Рассмотрены альтернативы (reuse-first), а не один вариант.
- Показаны потоки данных и контракты (опора на C4).
- Названы узкие места, деградация, бэкапы.
- Риски и открытые вопросы честно перечислены.
Частые ошибки
- Сразу дизайн, без требований. → Сначала NFR (нагрузка/latency) — они диктуют решение.
- Один вариант. → Покажи альтернативы и почему отвергнуты (reuse-first).
- Нет узких мест и деградации. → «А что под нагрузкой / при отказе?» — обязательный раздел.
- Документ-надгробие (написали и забыли). → SDD для обсуждения ДО кода, обновляй по ходу.
- Замолчали риски. → Открытые вопросы лучше назвать, чем встретить в проде.