Как делать11 октября 2026 г.9 мин чтения
Архитектура ПОШаг 1 из 9

Архитектура ПО: что это и какие решения в неё входят

Коротко

Архитектура программного обеспечения — это набор значимых решений о системе, которые дорого менять: как она делится на модули, где хранит данные, с какими системами интегрируется и как развёртывается. Каждое такое решение — компромисс между атрибутами качества: надёжностью, безопасностью, производительностью, стоимостью и простотой изменений. Решения показывают диаграммами (например, по C4-модели) и записывают с причинами в ADR — короткие документы в репозитории.

ОсновыУровень: СреднийОсновы архитектуры

После материала вы сможете

  • отличить архитектурное решение от детали реализации по тому, сколько стоит его изменить
  • связать решения проекта — границы модулей, хранение данных, интеграции, развёртывание — с атрибутами качества и назвать цену каждого
  • нарисовать диаграммы контекста и контейнеров по C4-модели с подписанными связями
  • оформить решение в виде ADR по шаблону Майкла Найгарда и заменить устаревшее решение новым ADR

Проверено на

C4 model (c4model.com)ADR: Michael Nygard format (2011)markdownlint-cli2 0.23.3 (markdownlint 0.41.1)

Сверено с документацией: 11 октября 2026 г.

Содержание
  1. 01Архитектура — это решения, которые дорого менять
  2. 02Атрибуты качества: что должна выдерживать система
  3. 03Компромиссы вместо «лучших практик»
  4. 04Модули и границы
  5. 05Нарисовать систему: C4-модель
  6. 06ADR: записывать решения и их причины
  7. 07Эволюция: архитектура растёт вместе с продуктом

Архитектура — это решения, которые дорого менять

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

Мартин Фаулер в колонке «Who Needs an Architect?» (IEEE Software, 2003) разбирает два определения Ральфа Джонсона. Первое: архитектура — это общее понимание устройства системы, которое разделяют ведущие разработчики. Второе: это решения, которые хотелось бы принять правильно в самом начале проекта. Люди хотят принять их рано, потому что считают их трудными для изменения, — отсюда рабочее определение «то, что считают трудным для изменения» и итог Фаулера: архитектура — это про важное, что бы это ни было.

Практичный фильтр дал Майкл Найгард в статье об ADR (2011): архитектурно значимы решения, которые влияют на структуру системы, её нефункциональные характеристики, зависимости, интерфейсы или технику построения.

Одно приложение или несколько сервисов

Архитектурное?
Да
Почему
Меняет сборку, развёртывание, мониторинг и границы транзакций

PostgreSQL или документная база для записей

Архитектурное?
Да
Почему
Переписываются запросы и модель данных, нужна миграция

Как узнаём об оплате: вебхук или периодический опрос

Архитектурное?
Да
Почему
Интерфейс с внешней системой, влияет на надёжность

Где хранятся сессии и как проверяется вход

Архитектурное?
Да
Почему
Безопасность, затрагивает каждый запрос

Какая библиотека форматирует даты

Архитектурное?
Обычно нет
Почему
Меняется в одном месте, если спрятана за своей функцией

Имена переменных и стиль кода

Архитектурное?
Нет
Почему
Меняется рефакторингом и линтером
Примеры для сервиса онлайн-записи в салон

Атрибуты качества: что должна выдерживать система

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

Удобная рамка — пять столпов Azure Well-Architected Framework от Microsoft: надёжность, безопасность, оптимизация затрат, операционное совершенство и эффективность производительности. Рамка написана для облака, но её вопросы подходят любой системе. Добавим шестой атрибут — изменяемость, то есть сколько стоит внести изменение. Фаулер подчёркивает, что высокое внутреннее качество не замедляет, а ускоряет поставку функций: в коде меньше «мусора», который мешает его понять.

Надёжность

Вопрос к системе
Что будет при сбое одной из частей?
Пример требования для сервиса записи
Запись сохраняется, даже если Telegram не отвечает; напоминание уйдёт позже

Безопасность

Вопрос к системе
Кто к чему имеет доступ?
Пример требования для сервиса записи
Мастер видит только свои записи; телефоны клиентов не попадают в логи

Производительность

Вопрос к системе
Сколько ждёт пользователь под нагрузкой?
Пример требования для сервиса записи
Свободные слоты открываются без задержек в вечерний пик записи

Затраты

Вопрос к системе
Сколько стоит работа системы?
Пример требования для сервиса записи
Нет серверов, которые простаивают ради редких пиков

Эксплуатация

Вопрос к системе
Как узнать о проблеме и выпустить исправление?
Пример требования для сервиса записи
Ошибки видны в мониторинге, релиз откатывается одной командой

Изменяемость

Вопрос к системе
Сколько стоит новая функция?
Пример требования для сервиса записи
Новый способ оплаты добавляется без правок в модуле записей

Компромиссы вместо «лучших практик»

Атрибуты качества конфликтуют: улучшая один, почти всегда платишь другим. В Well-Architected Framework у каждого столпа есть отдельная страница компромиссов. Несколько примеров из раздела о производительности:

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

Вопрос «как правильно?»

  • Ищет универсальный ответ
  • Копирует архитектуру крупных компаний
  • Добавляет компоненты «на вырост»
  • Не говорит, когда решение пересмотреть

Вопрос «чем платим?»

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

Поэтому фраза «так лучше» в архитектуре звучит подозрительно. Рабочая формулировка — «для нашей нагрузки и нашей команды мы выбираем X ради атрибута A и принимаем цену B». Именно её записывают в ADR, о котором речь ниже.

Модули и границы

Модуль — часть системы с одной зоной ответственности и явным публичным интерфейсом. Граница модуля отвечает на вопрос, что снаружи можно использовать, а что является его внутренним устройством. Для сервиса записи естественные модули совпадают с языком бизнеса: «Записи», «Расписание», «Уведомления», «Оплата».

  • Модуль владеет своими данными: таблицы платежей читает и меняет только «Оплата»
  • Соседи обращаются к нему через публичный интерфейс — функции, события или API, а не через внутренние файлы
  • Зависимости между модулями направлены в одну сторону и не образуют цикл
  • Изменение внутри модуля не требует правок в соседних
  • Модуль можно протестировать, подменив соседей заглушками

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

Внутри backend-модуля код обычно делят ещё и на слои: контроллер принимает HTTP, сервис держит бизнес-правила, репозиторий работает с базой. Это следующий уровень приближения — его разбирает урок о слоях backend-приложения.

Нарисовать систему: C4-модель

Архитектуру нужно уметь показать: новому разработчику, заказчику, себе через полгода. C4-модель Саймона Брауна предлагает рисовать систему как карту с масштабом — четыре уровня приближения, от общего вида до кода. Модель не зависит от нотации и инструмента: подойдут и маркерная доска, и любой редактор диаграмм.

  1. 01Контекст (System Context)Система целиком, её пользователи и внешние системы. Понятна и не техническим людям
  2. 02Контейнеры (Container)Приложения и хранилища данных внутри системы, технологии и протоколы между ними
  3. 03Компоненты (Component)Модули внутри одного контейнера и их ответственность
  4. 04Код (Code)Классы и функции. Лучше генерировать в IDE, чем рисовать вручную
Четыре уровня C4: каждый следующий раскрывает один элемент предыдущего

Сайт c4model.com рекомендует диаграммы контекста и контейнеров всем командам. Диаграмму компонентов советует рисовать, только если она добавляет ценность, а для долгоживущей документации — генерировать автоматически. Диаграмму кода для долгоживущей документации не рекомендует: IDE строит её по запросу. Начнём с контекста сервиса записи.

  1. 01Клиент салона
  2. 02Сервис онлайн-записи
  3. 03Telegram Bot API
Диаграмма контекста (упрощённо): клиент записывается через сервис, сервис отправляет напоминания через Telegram. Администратор салона и платёжный провайдер — связи того же уровня

Уровень контейнеров раскрывает «Сервис онлайн-записи»: из каких запускаемых частей он состоит и как они общаются.

  1. 01Браузер клиента
  2. 02Веб-приложение (Next.js)
  3. 03API записи (Node.js)
  4. 04База данных (PostgreSQL)
Диаграмма контейнеров: путь запроса на запись. API записи также отправляет напоминания в Telegram Bot API

Веб-приложение

Тип и технология
Контейнер: Next.js
Ответственность
Экраны записи для клиента и расписание для администратора
Связи
Вызывает API записи (JSON через HTTPS)

API записи

Тип и технология
Контейнер: Node.js
Ответственность
Модули «Записи», «Расписание», «Уведомления», «Оплата»; фоновая отправка напоминаний
Связи
Читает и пишет данные (SQL); отправляет напоминания в Telegram Bot API (HTTPS)

База данных

Тип и технология
Контейнер: PostgreSQL
Ответственность
Записи, слоты, клиенты, очередь напоминаний
Связи
—

Telegram Bot API

Тип и технология
Внешняя система
Ответственность
Доставка напоминаний клиенту
Связи
—
Элементы диаграммы контейнеров — то, что подписывают на самой схеме
  • У диаграммы есть заголовок с типом и областью: «Диаграмма контейнеров: сервис онлайн-записи»
  • Есть легенда: что означают формы, цвета, линии и стрелки
  • У каждого элемента указан тип, у контейнеров и компонентов — технология
  • Каждая стрелка однонаправленная и подписана конкретно: не «использует», а «отправляет напоминания через HTTPS»

ADR: записывать решения и их причины

Диаграмма показывает, что построено, но не объясняет почему. Через год новый разработчик увидит монолит и спросит, почему не микросервисы. Майкл Найгард описал два плохих исхода: слепо принять старое решение, не понимая его, или слепо поменять, сломав то, ради чего его принимали. Его ответ — Architecture Decision Record (ADR), короткая запись об одном архитектурном решении и его причинах.

ADR хранят в репозитории рядом с кодом, в Markdown, и нумеруют по порядку; номера не переиспользуют. Объём — одна-две страницы: по словам Найгарда, большие документы никто не читает и никто не обновляет. Формат состоит из пяти частей.

  1. Название

    Номер и короткая фраза о решении: «ADR 0002: Модульный монолит для сервиса записи».

  2. Контекст

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

  3. Решение

    Ответ на эти силы полными предложениями в активном залоге: «Мы будем…».

  4. Статус

    «Предложено», пока команда не согласовала, затем «Принято». Позже — «Устарело» или «Заменено» со ссылкой на новый ADR.

  5. Последствия

    Каким станет контекст после решения: что упростится и что усложнится. Все последствия, а не только положительные.

docs/adr/template.md
# ADR NNNN: Короткая фраза о решении

## Контекст

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

## Решение

Что мы делаем. Полные предложения в активном залоге: «Мы будем…».

## Статус

Предложено | Принято | Устарело | Заменено ADR NNNN

## Последствия

Что станет проще и что станет сложнее после решения.
Все последствия, а не только положительные.
Шаблон по формату Майкла Найгарда, порядок разделов — как в исходной статье
docs/adr/0002-modulnyj-monolit.md
# ADR 0002: Модульный монолит для сервиса записи

## Контекст

Сервис онлайн-записи в салоны: клиент выбирает услугу, мастера и время,
администратор видит расписание, клиент получает напоминание в Telegram.
Команда — три разработчика, релиз раз в неделю. Модули «Записи»,
«Расписание», «Уведомления» и «Оплата» выделены, но их границы проверены
только на одном салоне. Запись не должна теряться, если Telegram недоступен.

## Решение

Мы будем развёртывать серверную часть как одно приложение Node.js с одной
базой PostgreSQL; веб-интерфейс на Next.js остаётся отдельным приложением.
Каждый модуль лежит в своей папке, владеет своими таблицами и открывает
другим модулям только публичный интерфейс. Импорт внутренних файлов чужого
модуля запрещает линтер в CI. Напоминания отправляет фоновая задача: запись
сохраняется в базе сразу, отправка повторяется при сбое Telegram.

## Статус

Принято, 2026-10-11. Заменяет ADR 0001 «Отдельный сервис уведомлений».

## Последствия

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

Модули нельзя масштабировать и выпускать по отдельности: исправление в
«Оплате» требует релиза всего приложения. Границы держатся на дисциплине и
проверке импортов; без неё монолит станет «клубком».

Если модулю понадобится своё масштабирование или отдельная команда, мы
вынесем его в сервис и оформим это новым ADR, который заменит этот.
Учебный пример ADR для сервиса записи. Оба файла проходят markdownlint-cli2 с настройками по умолчанию

Шаблон Найгарда — не единственный. Каталог на adr.github.io и репозиторий Джоэла Паркера Хендерсона собирают и другие: MADR с явным списком рассмотренных вариантов и их плюсов и минусов, Y-statements — решение в одном структурированном предложении, подробный шаблон Тайри и Акермана. Важнее регулярность, чем выбор шаблона. Писать ADR на каждое решение не нужно: временный обходной путь, прототип или эксперимент с ограниченным риском и ценой документа не требуют.

Эволюция: архитектура растёт вместе с продуктом

Архитектуру не утверждают один раз навсегда. Фаулер приводит письмо Джонсона: в программах нет теоретической причины, по которой что-то трудно изменить. Любую отдельную часть можно сделать лёгкой для изменения, но каждая такая часть немного усложняет систему, а если сделать гибким всё, система станет очень сложной — сложность же и делает программы трудными для изменения. Поэтому одна из главных задач архитектора, по Фаулеру, — убирать необратимость там, где она обходится дорого, а не делать гибким всё подряд.

  • Откладывайте дорогие решения, пока не хватит информации, но не дольше: «разберёмся потом» — тоже решение, и его стоит записать
  • Прячьте то, что вероятно изменится, за своим интерфейсом: платёжного провайдера, канал уведомлений, файловое хранилище
  • Пересматривайте ADR, когда меняются условия из раздела «Контекст»: выросла команда или нагрузка, появилось требование регулятора
  • Обновляйте диаграммы контекста и контейнеров вместе с кодом — они меняются редко, поэтому поддерживать их дёшево

Дальше в направлении — принципы, по которым проводят границы внутри кода: SOLID, а затем паттерны проектирования, которые реализуют эти границы на практике.

Как проверено2 · пройденосверено 11 октября 2026 г.
  • запущено, работает

    docs/adr/template.md (RU и EN) — шаблон ADR в формате Найгарда

    markdownlint-cli2 0.23.3 (markdownlint 0.41.1), настройки по умолчанию: 0 issues; структура разделов сверена со статьёй Найгарда

  • запущено, работает

    docs/adr/0002-modulnyj-monolit.md / 0002-modular-monolith.md — пример ADR

    markdownlint-cli2 0.23.3, настройки по умолчанию: 0 issues; код в статье вставлен из проверенных файлов скриптом сборки

«Запущено» — код выполнен во временном проекте или контейнере, вывод в статье взят из прогона. «Частично» — проверено с заглушками вместо внешних сервисов. «Не запускалось» — нужны устройство, аккаунт или ключ; шаги сверены с официальной документацией. Файлы проверочного проекта и логи запусков сохранены в архиве InterLAB.

Расскажите о задаче — мы изучим запрос и свяжемся с вами

Есть задача?
Обсудим и оценим — бесплатно.

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

  • Оценка объёма и рисков до старта
  • NDA — по вашему или нашему шаблону
  • Старт работ в течение недели

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

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