Konstantin Shulga
СтатьиОбо мне
СтатьиОбо мне
Язык
Theme

Konstantin Shulga

Размышления и практические уроки об архитектуре программного обеспечения, принятии технических решений, практиках разработки и инженерном лидерстве.

  • EN
  • RU

Ссылки

  • GitHub
  • LinkedIn

Документы

  • Политика конфиденциальности
  • Условия использования

Язык

© 2026 Konstantin Shulga. Все права защищены.

Cookies и аналитика

Мы используем cookies для измерения трафика и улучшения сайта. Google Analytics и Яндекс.Метрика могут собирать данные об использовании. Подробнее — в Политике конфиденциальности.

К списку статей

Системный подход к проектированию архитектуры

15 июня 2026 г.8 мин чтения

  • system design

Summary

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

На примере системы уведомлений для банка рассмотрим четыре ключевых этапа: сбор требований, оценку масштаба системы, построение High-Level Design и детальную проработку архитектуры.

Разберем, как требования влияют на выбор архитектурных решений, зачем нужны приблизительные расчеты нагрузки и почему проектирование всегда связано с поиском компромиссов. Подход одинаково полезен как при работе над реальными проектами, так и при подготовке к секции System Design на собеседованиях.

Contents

  • Когда стоит применять этот подход
  • Крупные системы и высокая неопределенность
  • Использование на этапе System Design при собеседовании
  • Этапы проектирования архитектуры
  • Этап 1. Понять проблему
  • Этап 2. Back-of-Envelope Estimation
  • Этап 3. Построить High-Level Design
  • Этап 4. Детальная проработка архитектуры
  • Почему не существует идеальной архитектуры

Когда появляется задача спроектировать архитектуру системы, многие инженеры не понимают, с чего начать. Кто-то сразу начинает рисовать схемы, кто-то выбирает технологии, а кто-то пытается написать прототип.

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

В этой статье хочу описать подход, который помогает структурировать процесс проектирования. Его можно использовать как в реальной работе, так и при прохождении секции System Design на собеседованиях.

Когда стоит применять этот подход

Крупные системы и высокая неопределенность

Подход, описанный ниже, в первую очередь рассчитан на проектирование относительно крупных систем или задач с высокой степенью неопределенности. Если речь идет о небольшом сервисе с понятными требованиями и ограниченным сроком жизни, прохождение всех этапов может оказаться избыточным и только увеличить Time To Market.

Архитектура всегда является компромиссом между качеством проработки и скоростью поставки решения.

Использование на этапе System Design при собеседовании

Этот подход хорошо работает и на собеседованиях. При этом важно помнить, что интервью обычно ограничено по времени. Никто не ожидает, что за 45–60 минут вы спроектируете систему, над которой в реальности работали сотни инженеров на протяжении нескольких лет.

Ваша задача — показать ход мыслей, умение выявлять требования, анализировать компромиссы и принимать инженерные решения. Поэтому глубину проработки каждого этапа необходимо определять исходя из времени, которое осталось на интервью.

Этапы проектирования архитектуры

Проектирование архитектуры редко является линейным процессом. По мере появления новой информации приходится возвращаться к предыдущим этапам, пересматривать предположения и корректировать принятые решения.

Тем не менее в большинстве случаев процесс можно представить в виде четырех основных этапов:

  1. Понять проблему и собрать требования.

  2. Оценить объемы и нагрузку.

  3. Построить верхнеуровневую архитектуру.

  4. Детально проработать отдельные компоненты системы.

Важно понимать, что это не четыре независимых шага. Требования влияют на оценки. Оценки влияют на архитектуру. Архитектура влияет на детали реализации. Каждое решение должно иметь обоснование в виде требований, ограничений или ожидаемой нагрузки.

Чтобы показать эту связь на практике, будем использовать единый пример на протяжении всей статьи.

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

На первый взгляд задача выглядит достаточно простой. Однако по мере погружения в детали выясняется, что за ней скрывается множество архитектурных решений и компромиссов.

Этап 1. Понять проблему

Первый вопрос, который стоит задать себе: Какую проблему мы вообще пытаемся решить?

Многие архитектурные ошибки появляются не из-за неудачного выбора технологий, а из-за неверного понимания самой задачи.

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

На этом этапе полезно активно задавать вопросы стейкхолдерам:

  • Кто будет пользоваться системой?

  • Какие сценарии являются основными?

  • Какие сценарии являются критичными?

  • Какие существуют ограничения?

  • Что считается успешным результатом?

Чем больше контекста вы получите, тем больше данных будет для принятия решений на следующих этапах.

Полезно проводить brainstorm-сессии со стейкхолдерами и будущими пользователями системы. Нередко в процессе обсуждений удается обнаружить скрытые требования или посмотреть на проблему под другим углом.

Вернемся к нашему примеру.

На первый взгляд задача звучит очень просто: нужно отправлять пользователям уведомления.

Но после общения со стейкхолдерами выясняется следующее:

  • уведомления используются для банковских операций;

  • поддерживаются push и email-каналы;

  • потеря уведомления недопустима;

  • большинство уведомлений должно доставляться менее чем за 30 секунд;

  • пользователь может иметь несколько устройств;

  • push-уведомления могут не доставляться внешним провайдером;

  • необходимо хранить историю доставки в течение 5 лет;

  • ожидается до 20 миллионов уведомлений в час в периоды пиковых нагрузок.

На основании полученной информации можно сформулировать требования.

Функциональные требования:

  • отправка push-уведомлений;

  • отправка email-уведомлений;

  • просмотр статуса доставки;

  • повторная отправка уведомлений;

  • аудит истории уведомлений.

Нефункциональные требования:

  • доставка большинства (90%) уведомлений менее чем за 30 секунд;

  • отсутствие потери сообщений;

  • высокая доступность системы;

  • сохранение истории доставки в течение 5 лет.

Архитектурные драйверы

Не все требования одинаково влияют на архитектуру. После сбора требований полезно выделить несколько ключевых драйверов — требований, которые будут определять большую часть архитектурных решений.

В нашем случае это:

  • отсутствие потери сообщений;

  • доставка менее чем за 30 секунд;

  • высокая доступность;

  • длительное хранение истории доставки.

Именно они будут влиять на большинство дальнейших решений.

Часто именно нефункциональные требования оказывают наибольшее влияние на архитектуру системы. Функционально две системы могут делать одно и то же, но требования к задержкам, доступности или объему нагрузки способны привести к совершенно разным архитектурным решениям.

Этап 2. Back-of-Envelope Estimation

Теперь у нас есть требования и понимание того, какие из них являются наиболее важными.

Следующая задача — оценить масштаб системы.

Цель этого этапа не получить точные цифры, а понять порядок величин и проверить жизнеспособность будущих решений.

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

Предположим, система должна обрабатывать до 20 миллионов уведомлений в час.

Получаем:

  • около 5 500 уведомлений в секунду в среднем;

  • при трехкратном пике — около 16 500 уведомлений в секунду;

  • средний размер уведомления — 4 КБ;

  • примерно 80 ГБ новых данных в час;

  • около 1.9 ТБ в сутки;

  • более 700 ТБ данных в год без учета репликации.

Эти цифры уже позволяют сделать несколько важных выводов.

Во-первых, хранение всей истории в дорогостоящих высокопроизводительных хранилищах может оказаться слишком дорогим.

Во-вторых, доставка уведомлений должна выполняться асинхронно, поскольку внешние провайдеры могут отвечать медленно или быть временно недоступны.

В-третьих, необходимо заранее учитывать масштабирование очередей, воркеров и хранилищ данных.

Важно понимать, что подобные расчеты нужны не ради самих расчетов. Они помогают быстро отбрасывать решения, которые не подходят под ожидаемый масштаб.

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

Этап 3. Построить High-Level Design

После оценок появляется понимание масштаба системы. Теперь можно принимать архитектурные решения, опираясь не на предположения, а на данные, полученные на предыдущих этапах.

На этом этапе определяются основные компоненты системы:

  • API;

  • базы данных;

  • очереди сообщений;

  • кэши;

  • внешние интеграции.

Важно не погружаться слишком глубоко в детали. Распространенная ошибка — начинать проектировать сложную распределенную систему раньше времени.

Я стараюсь придерживаться того же принципа, который использую при написании кода: KISS (Keep It Simple, Stupid). Если задачу можно решить проще, обычно стоит начать именно с простого решения.

Рассмотрим, как требования начинают влиять на архитектуру. Поскольку потеря уведомлений недопустима, потребуется надежный брокер сообщений с сохранением данных на диск. Необходимость отслеживать статус доставки приводит к появлению отдельного хранилища статусов. Медленная работа внешних провайдеров подталкивает к асинхронной обработке сообщений, а требования по пропускной способности делают необходимым горизонтальное масштабирование обработчиков.

В результате может появиться следующая схема:

High level design - Notification System
Верхнеуровневый дизайн системы уведомлений

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

Этап 4. Детальная проработка архитектуры

После появления верхнеуровневой схемы можно переходить к деталям реализации отдельных компонентов системы.

Если на этапе High-Level Design мы определяли основные части системы и связи между ними, то теперь необходимо понять, как именно система будет выполнять ключевые требования, сформулированные ранее.

В примере ключевыми требованиями остаются отсутствие потери уведомлений, доставка большинства сообщений менее чем за 30 секунд, высокая доступность системы и возможность отслеживать статус доставки. Именно вокруг этих требований будет строиться дальнейшая детализация архитектуры.

На этом этапе архитектура начинает превращаться из набора компонентов в конкретные технические решения.

Рассмотрим жизненный цикл уведомления внутри системы.

Notification Lifecycle
Схема жизненного цикла уведомления

Из этой схемы можно увидеть, как требования влияют на реализацию.

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

Далее сообщение обрабатывается воркером, который определяет канал доставки, формирует запрос к внешнему провайдеру и выполняет отправку.

После этого возможны два сценария:

Успешная доставка

Если провайдер подтверждает прием уведомления, система сохраняет статус доставки в базе данных. Сохранение статуса доставки позволяет показывать пользователю актуальное состояние уведомления, собирать статистику по качеству доставки и обеспечивать аудит операций.

Ошибка доставки

Если отправка завершается ошибкой, необходимо определить ее тип.

Временные ошибки могут возникать по различным причинам:

  • недоступность провайдера;

  • сетевые проблемы;

  • превышение лимитов запросов.

В подобных случаях сообщение не должно теряться. Вместо этого оно помещается в очередь повторных попыток и будет отправлено повторно через определенный промежуток времени.

Постоянные ошибки требуют другого подхода. Например, пользователь мог указать несуществующий email-адрес или удалить устройство, на которое отправляется push-уведомление. В таких ситуациях повторные попытки обычно не имеют смысла. Сообщение помещается в Dead Letter Queue (DLQ), где может быть проанализировано отдельно.

Дополнительные механизмы

По мере детализации архитектуры начинают появляться дополнительные механизмы надежности. Для защиты от дубликатов требуется идемпотентная обработка сообщений. Для временных ошибок добавляются retry-механизмы, а необрабатываемые сообщения могут попадать в Dead Letter Queue. Одновременно появляется необходимость мониторить длину очередей, настраивать алертинг, хранить состояние обработки и автоматически масштабировать воркеры при росте нагрузки.

Именно на этом этапе обычно появляются ответы на вопросы, которые невозможно решить при проектировании верхнеуровневой архитектуры.

Например:

  • Что произойдет при падении воркера во время обработки сообщения?

  • Как избежать повторной отправки одного и того же уведомления?

  • Где будет храниться состояние обработки?

  • Как система будет реагировать на недоступность внешнего провайдера?

  • Как обнаружить ситуацию, когда очередь начинает расти быстрее, чем обрабатываться?

Чем критичнее требования к надежности, доступности и производительности системы, тем больше подобных вопросов приходится прорабатывать.

В результате именно на этом этапе верхнеуровневая диаграмма постепенно превращается в полноценную архитектуру, готовую к реализации.

Компромиссы

Практически каждое решение имеет свою цену. Например, гарантированная доставка повышает надежность системы, но заметно усложняет ее реализацию. Хранение полной истории уведомлений увеличивает стоимость хранения данных. Репликация повышает доступность, однако требует дополнительных ресурсов. Асинхронная обработка помогает справляться с нагрузкой и сбоями внешних сервисов, но добавляет задержки. Практически каждое архитектурное решение приносит определенную выгоду, одновременно создавая новые ограничения.

Поэтому задача архитектора заключается не в поиске идеального решения, а в выборе наиболее подходящего набора компромиссов для конкретной задачи.

Итеративность проектирования

На практике проектирование редко проходит строго по описанным этапам.

Например, после выполнения оценок может оказаться, что стоимость хранения данных значительно превышает бюджет проекта.

Тогда придется вернуться к требованиям и уточнить:

  • действительно ли необходимо хранить данные 5 лет;

  • можно ли архивировать старые записи;

  • нужны ли быстрые запросы ко всей истории.

После изменения требований архитектура может существенно измениться. Поэтому проектирование представляет собой не линейную последовательность шагов, а набор итераций, в ходе которых постепенно уточняется понимание системы.

Ограничения реального мира

Архитектура редко проектируется в вакууме. На практике архитектура почти всегда ограничена существующим технологическим стеком компании, доступной инфраструктурой, экспертизой команды, вычислительными ресурсами и бюджетом проекта.

Поэтому не всегда оптимальное с технической точки зрения решение является оптимальным для бизнеса. Иногда разумнее выбрать технологию, которую команда хорошо знает, чем внедрять новую, даже если она выглядит привлекательнее на бумаге.

Если же преимущества новой технологии действительно оправдывают затраты, необходимо иметь сильные аргументы в пользу такого выбора.

Как и на предыдущих этапах, полезно показывать архитектуру коллегам и собирать обратную связь до начала реализации.

Почему не существует идеальной архитектуры

Проектирование архитектуры — одна из самых интересных и одновременно самых сложных инженерных задач. У архитектурных задач редко существует единственное правильное решение. Обычно есть набор компромиссов, среди которых приходится выбирать.

Принимая архитектурные решения, мы всегда опираемся на имеющийся опыт и делаем ставку на определенный вариант развития событий. Иногда эта ставка оказывается удачной, иногда нет.

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

Со временем приходит инженерное чутье. Оно формируется через практику, ошибки, успешные решения и постоянную работу с реальными системами.

Но независимо от опыта, системный подход позволяет сделать процесс проектирования более предсказуемым и значительно уменьшить вероятность принятия случайных архитектурных решений.

Contents

  • Когда стоит применять этот подход
  • Крупные системы и высокая неопределенность
  • Использование на этапе System Design при собеседовании
  • Этапы проектирования архитектуры
  • Этап 1. Понять проблему
  • Этап 2. Back-of-Envelope Estimation
  • Этап 3. Построить High-Level Design
  • Этап 4. Детальная проработка архитектуры
  • Почему не существует идеальной архитектуры