← назад к разделу

Системный дизайн кажется искусством, пока не разложен в процедуру. На деле это метод — последовательность шагов, у каждого из которых есть конкретный результат. Эта статья — сам метод; строительные блоки и сквозной пример — в соседних.

Почему нельзя сразу рисовать квадратики

Типичная ошибка: архитектор слышит задачу и сразу начинает рисовать компоненты. Через десять минут на доске красивая схема — и никто не знает, выдержит ли она 10 000 запросов в секунду или 100, зачем там три очереди и что произойдёт, если упадёт база.

Проблема в том, что схема нарисована до того, как заданы вопросы. Метод ниже задаёт их в правильном порядке.

Шаг 1. Функциональные требования

Что система делает: 5–8 главных сценариев словами пользователя. «Отправить уведомление в push и email», «пользователь управляет подписками», «продукт видит статистику доставки».

Важно зафиксировать и анти-требования — чего сознательно не делаем. Без них объём дизайна определяет самый тревожный участник обсуждения: «а что если пользователей будет миллиард?», «а если хотят работать в оффлайне?» — и система разрастается бесконечно.

Результат шага: список сценариев + список того, что выходит за рамки.

Шаг 2. Нефункциональные требования

Это числа и обязательства, из которых вырастает весь дальнейший дизайн:

  • Нагрузка: сколько запросов в секунду на запись и чтение, каков пик относительно среднего.
  • Объёмы: размер одной записи × количество записей × срок хранения = место на диске; как растёт за год.
  • Скорость ответа: целевые показатели на ключевые операции.
  • Доступность: что случится при отказе и сколько «девяток» реально нужно (каждая девятка в четыре девятки — это в 10 раз дороже трёх девяток).
  • Согласованность данных: где нужна строгая («прочитал то, что только что записал»), где достаточно получить обновлённые данные чуть позже — по каждой операции, не «вообще».

Требования, которые бизнес не назвал, назначаются явно как допущения — и записываются. Проектирование под невысказанные требования — главный источник избыточной сложности.

Шаг 3. Оценки на салфетке

Back-of-envelope — грубая арифметика, которая отсекает целые классы решений ещё до того, как нарисован первый квадратик:

100 млн уведомлений/день ≈ 1200/сек в среднем, пик ×5 ≈ 6000/сек
Запись ~1 КБ → 100 ГБ/день → 36 ТБ/год сырых данных
Чтение истории: 10 млн активных пользователей × 5 заходов ≈ 600 RPS чтения

Точность ±50% достаточна: оценка нужна, чтобы выбрать класс решения (одна PostgreSQL-база / PostgreSQL с партиционированием / отдельное хранилище под историю), а не конкретный сервер. Считать стоит на пике, а не на среднем — системы падают именно на пиках.

Шаг 4. Контракты

API ключевых операций: адреса или события, структуры запросов и ответов, идемпотентность, коды ошибок — на уровне сигнатур, без полной спецификации.

Зачем контракт раньше схемы компонентов: он обнаруживает скрытые требования. «А как клиент узнаёт статус доставки?» — этот вопрос, заданный при проектировании контракта, добавляет в дизайн новую операцию. Если его не задать сейчас, она всплывёт в коде — переделывать дороже.

Шаг 5. Модель данных

Главные сущности, их ключи, объёмы и паттерны доступа. Паттерны доступа — это ответ на вопросы: что читается по ключу, что фильтруется, что агрегируется, что только дописывается. По этим ответам выбирается хранилище, а не по привычке.

Здесь же — владение данными: какая часть системы является источником правды для каждой сущности.

Шаг 6. Схема: компоненты и поток

Только теперь — квадратики. Компоненты, их обязанности, синхронные и асинхронные связи. На каждую стрелку стоит ответить: это синхронный вызов или асинхронное событие? Выбор влияет на поведение при отказах и задержку.

Хорошая проверка готовой схемы — прогнать по ней каждый сценарий из шага 1 пальцем: «запрос пришёл сюда, дальше очередь, дальше...». Сценарий, который не проходит по стрелкам, — дыра в дизайне.

Шаг 7. Горячие точки

В каждой системе есть 1–2 места, где концентрируется сложность: самая нагруженная таблица, компонент с состоянием, точка слияния потоков. Метод требует их назвать и углубиться: ключи шардирования, схема горячей таблицы, поведение очереди при отставании потребителей.

Остальное дизайнится крупными мазками — углубляться везде одинаково означает не углубиться нигде.

Шаг 8. Поведение при отказах

По каждому компоненту: что видит пользователь, когда этот компонент недоступен? Какие операции продолжают работать в упрощённом режиме, какие останавливаются, что накапливается и где?

Здесь важна связь с идемпотентностью: если система умеет повторять запросы при сбое, повторные запросы не должны создавать дубликаты. Это свойство дизайна — его не добавить «потом».

Шаг 9. Эволюция

Не «дизайн на 10 лет», а честная проверка: какое из принятых решений будет больно менять? Такие места стоит защитить интерфейсом; остальное переживёт рефакторинг. Плюс — явный план первой версии: что строим сейчас, что сознательно откладываем.

Принципы, которые удерживают метод

Четыре принципа, нарушение любого из которых обесценивает остальное:

  1. Дизайн — производная от ограничений. Нет «правильной архитектуры уведомлений вообще»; есть архитектура под 100 тысяч уведомлений в день и под 100 миллионов — и это разные системы.
  2. Числа решают споры. «Потянет ли PostgreSQL?» — не вопрос мнений: считается на салфетке за две минуты. Любое «кажется, не потянет» обязано превратиться в оценку.
  3. Простейшее достаточное. Каждый компонент в схеме должен оправдываться требованием, а не привычкой или модой.
  4. Компромисс называется вслух. Каждое решение что-то получает и чем-то платит; дизайн без списка «чем платим» — реклама, не инженерия.

Коротко

  • Нельзя рисовать компоненты до числовых требований — схема не имеет ответа, рассчитана ли она на реальную нагрузку.
  • Функциональные требования фиксируют и что делаем, и что сознательно не делаем.
  • Оценка на салфетке с точностью ±50% отсекает целые классы решений, считать нужно на пике.
  • Контракт API проектируется до схемы компонентов — он обнаруживает скрытые операции.
  • Хранилище выбирается по паттернам доступа, не по привычке.
  • Схему компонентов проверяют, прогоняя по ней каждый сценарий вручную.
  • В каждой системе 1–2 горячие точки — их разбирают глубоко, остальное крупными мазками.
  • Поведение при отказах — это часть дизайна, не доработка после запуска.

Что почитать дальше

  • Строительные блоки системного дизайна — словарь компонентов, из которого собирается шаг 6.
  • Сквозной пример: система уведомлений — весь метод на одной задаче.
  • Оформление и защита дизайна — как превратить результат в документ.