Аппендикс
Аппендикс D

Справочник архитектурных паттернов

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

Паттерны сгруппированы по происхождению и уровню абстракции — от GoF-паттернов до высокоуровневых архитектурных стилей распределённых систем.


#1. Порождающие паттерны (GoF Creational)

Паттерны из оригинального каталога Gang of Four, управляющие созданием объектов. В веб-архитектуре чаще встречаются в инфраструктурном коде, DI-контейнерах и фреймворках, чем в бизнес-логике.


#1.1 Singleton (Одиночка)

Описание: Гарантирует, что у класса есть ровно один экземпляр, и предоставляет глобальную точку доступа к нему. Самый цитируемый и одновременно самый критикуемый паттерн GoF. В веб-приложениях синглтонами обычно управляет DI-контейнер или фреймворк, а не разработчик вручную. Под капотом: connection pool'ы, кэши, логгеры, регистри сервисов.

Когда применять: Ресурсоёмкие объекты, которые должны жить в единственном экземпляре (connection pool, кэш, фабрика сессий). Когда нужна единая точка координации (реестр сервисов, логгер).

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

Глава: 3 (Первые принципы архитектуры), 12 (Модульный монолит)


#1.2 Factory (Фабрика)

Описание: Инкапсулирует логику создания объектов в отдельном методе или классе. Вместо new Something(params) вызываешь фабрику: она сама решает, какой конкретный класс создать и как его сконфигурировать. Три вариации: Simple Factory (один метод), Factory Method (подклассы решают), Abstract Factory (семейство фабрик).

В веб-мире фабрики — основа DI-контейнеров, построителей HTTP-клиентов, фабрик репозиториев для разных БД.

Когда применять: Создание объекта требует сложной логики или конфигурации. Хочешь скрыть от вызывающего кода, какой конкретный класс создаётся (например, разные реализации под разные environment'ы).

Когда не применять: new Something() отлично работает. Фабрика добавляет абстракцию, которая никогда не меняется — YAGNI. Фабрика фабрик — признак over-engineering.

Глава: 3 (Первые принципы архитектуры)


#1.3 Abstract Factory (Абстрактная фабрика)

Описание: Фабрика фабрик. Предоставляет интерфейс для создания семейств связанных объектов без указания их конкретных классов. Каждая конкретная фабрика производит целое «семейство» продуктов, гарантируя их совместимость.

В веб-мире: фабрика DAO для разных БД (PostgreSQL vs MySQL), провайдеры для разных облачных платформ (AWS vs GCP), UI-компоненты для разных тем.

Когда применять: Система должна работать с разными семействами продуктов (база данных, облачный провайдер, UI-тема). Нужно гарантировать, что объекты из одного семейства используются вместе (нельзя взять AWS SQS в GCP-стеке).

Когда не применять: Есть только одна конкретная фабрика. Разные «семейства» на самом деле не связаны — достаточно обычной Factory. Добавляет сложность, которая не оправдана количеством вариаций.

Глава: 3 (Первые принципы архитектуры)


#1.4 Builder (Строитель)

Описание: Отделяет конструирование сложного объекта от его представления. Пошагово создаёт объект, позволяя настраивать только нужные параметры. Chain of methods (builder.setHost().setPort().setCredentials().build()) — это он.

Классика веба: построение HTTP-запроса, SQL-запроса, конфигурация подключения к БД. Альтернатива телескопическим конструкторам с десятком параметров.

Когда применять: Объект имеет много (5+) параметров, особенно опциональных. Конструктор с 10 параметрами превращается в кошмар. Нужно создавать разные представления одного процесса построения.

Когда не применять: Объект простой (2-3 параметра) — хватит конструктора. Builder используется «на всякий случай». В языках с именованными параметрами и дефолтными значениями Builder часто избыточен.

Глава: 3 (Первые принципы архитектуры)


#2. Структурные паттерны (GoF Structural)

Паттерны, определяющие, как классы и объекты собираются в структуры. В веб-архитектуре — основа интеграционных слоёв, обёрток и прокси.


#2.1 Adapter (Адаптер)

Описание: Позволяет объектам с несовместимыми интерфейсами работать вместе. Как переходник для зарядки — вилка Type-C к старому USB. В веб-архитектуре адаптеры оборачивают внешние сервисы, SDK, библиотеки в унифицированный интерфейс.

Hexagonal Architecture буквально построена на адаптерах: port — это интерфейс, adapter — реализация. PostgresOrderRepository и RedisOrderCache — адаптеры к одному порту OrderRepository.

Когда применять: Интеграция с легаси-системой. Подмена внешнего сервиса без изменения кода (сменили Stripe на Adyen — переписали только адаптер). Тестирование — адаптер к внешнему API легко мокается. Ports & Adapters.

Когда не применять: Адаптер ради адаптера — «а вдруг мы поменяем БД» чаще всего остаётся гипотезой, а код усложняется навсегда. Можно изменить вызываемый код — сделайте это, а не оборачивайте.

Глава: 6 (API-архитектура), 12 (Модульный монолит), 18 (Service Mesh)


#2.2 Facade (Фасад)

Описание: Предоставляет простой интерфейс к сложной подсистеме. Не скрывает подсистему полностью (в отличие от Adapter), а даёт удобную точку входа для самых частых операций. Как пульт от телевизора — внутри сложная электроника, снаружи шесть кнопок.

Веб-пример: класс OrderService, который под капотом дёргает InventoryClient, PaymentGateway, NotificationService и EmailSender. Клиент (контроллер) видит только orderService.placeOrder().

Когда применять: Есть сложная подсистема, но клиенту нужен простой интерфейс для 80% сценариев. Хочешь уменьшить связанность между подсистемами. Нужна единая точка входа для тестирования.

Когда не применять: Клиенту нужен полный контроль над подсистемой — фасад будет мешать. Фасад становится God Object, через который идёт вся работа. Подсистема и так простая — фасад добавит только лишний вызов.

Глава: 12 (Модульный монолит), 15 (Микросервисы — API Gateway как фасад)


#2.3 Proxy (Заместитель)

Описание: Предоставляет заменитель другого объекта, контролируя доступ к нему. От Adapter отличается тем, что сохраняет тот же интерфейс (не переводит, а перехватывает). Может добавлять логирование, кэширование, lazy initialization, проверку прав — не меняя код целевого объекта.

В вебе: lazy-loading в ORM (Hibernate proxy), кэширующий прокси перед API, reverse proxy (Nginx, Envoy) перед сервисами.

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

Когда не применять: Прокси добавляет latency без реальной пользы. Объект лёгкий и всегда нужен — lazy-loading не имеет смысла. Есть более простой способ (middleware, декоратор).

Глава: 15 (Микросервисы), 18 (Service Mesh — sidecar proxy), 21 (Кэширование)


#3. Поведенческие паттерны (GoF Behavioral)

Паттерны, определяющие способы коммуникации между объектами. Observer и Pub/Sub — фундамент event-driven архитектуры. Strategy и Template Method — основа гибкости бизнес-логики.


#3.1 Observer (Наблюдатель)

Описание: Определяет зависимость «один-ко-многим»: когда один объект (subject) меняет состояние, все зависимые (observers) уведомляются автоматически. Синхронный, in-process.

В веб-мире: EventEmitter в Node.js, слушатели событий в браузере, сигналы в Django, Rails callbacks — всё это Observer. Внутренняя шина событий в монолите.

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

Когда не применять: Когда нужно гарантировать доставку — Observer в памяти не переживёт падение процесса. Нужна коммуникация между сервисами — это Pub/Sub. Логика подписчиков может создавать циклы (A → B → C → A), которые сложно отлаживать.

Глава: 4 (DDD — Domain Events), 16 (Event-Driven Architecture)


#3.2 Pub/Sub (Publisher-Subscriber, Издатель-Подписчик)

Описание: Эволюция Observer для распределённых систем. Издатель отправляет сообщение в канал (topic), не зная подписчиков. Подписчики получают сообщения через брокер. Полная развязка — издатель и подписчик ничего не знают друг о друге.

Разница с Observer: Pub/Sub работает через посредника (брокер), обеспечивает слабую связанность (loose coupling) и может быть跨процессным. Observer — синхронный и in-process.

Когда применять: Коммуникация между микросервисами (Kafka, RabbitMQ, SNS). Одно событие — много потребителей (notifications, audit, analytics). Нужна слабая связанность. Асинхронная обработка.

Когда не применять: Нужен синхронный ответ — Pub/Sub асинхронен по природе. Все события в один topic — подписчики получают мусор и фильтруют на своей стороне. Schema событий не управляется — со временем никто не знает формат.

Глава: 16 (Event-Driven Architecture), 22 (Асинхронность и очереди)


#4.1 Strategy (Стратегия)

Описание: Определяет семейство алгоритмов, инкапсулирует каждый и делает их взаимозаменяемыми. Клиент выбирает стратегию, не зная её реализации. Алгоритм можно подставить на лету (runtime) или через конфигурацию.

В веб-архитектуре: разные алгоритмы аутентификации (JWT, OAuth, SAML), разные форматы экспорта (PDF, CSV, Excel), разные стратегии кэширования, разные провайдеры платежей с общим интерфейсом.

Когда применять: Есть несколько вариантов поведения, которые выбираются в рантайме или конфигом. Много if/else или switch по типу — Strategy выносит каждую ветку в отдельный класс. Нужно добавлять новые варианты без изменения существующего кода (Open/Closed Principle).

Когда не применять: Варианта два и они никогда не меняются — if проще. Каждая стратегия — три строки кода. Стратегии — это просто enum с флагами.

Глава: 9 (Аутентификация и авторизация), 21 (Кэширование), 24 (Resilience)


#4.2 Template Method (Шаблонный метод)

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

В веб-мире: базовый класс BaseService с последовательностью validate() → process() → notify() → log(), где каждый шаг — переопределяемый хук. CI/CD pipeline, миграции БД (up() / down()), middleware chain.

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

Когда не применять: Последовательность шагов разная — Template Method загонит в рамки. Все шаги реализованы одинаково — общая реализация проще. Наследование ради наследования — композиция часто лучше (Strategy вместо Template Method).

Глава: 13 (CI/CD для монолита), 6 (API-архитектура)


#5. Архитектурные паттерны UI

Паттерны организации кода на клиенте. Эволюционировали от MVC к MVVM по мере усложнения фронтенда. В современных фреймворках (React, Vue, Angular) их элементы смешаны, но базовые принципы остаются.


#5.1 MVC (Model-View-Controller)

Описание: Классическая трёхзвенка UI. Model — данные и бизнес-логика. View — отображение. Controller — обработка ввода пользователя и координация.

Веб-версия (Server-Side MVC): Rails, Django, Spring MVC. Контроллер принимает HTTP-запрос, дёргает Model, передаёт данные в View (шаблон), View рендерит HTML. Самый распространённый паттерн в серверном вебе.

Когда применять: Server-rendered веб-приложения. Команда знает MVC (а её знает почти каждый). Как стартовая архитектура — проверено десятилетиями.

Когда не применять: Сложный интерактивный UI — Controller становится God Object. В SPA лучше компонентная модель (React/Vue/Svelte). Controller содержит бизнес-логику вместо Model (Fat Controller — анти-паттерн).

Глава: 2 (Краткая история веб-архитектуры), 8 (Фронтенд-архитектура)


#5.2 MVP (Model-View-Presenter)

Описание: Вариация MVC, где Presenter полностью управляет View через интерфейс. View — пассивная: просто отображает то, что сказал Presenter. Presenter содержит логику представления и обрабатывает события View.

Отличие от MVC: Presenter знает о View (у него есть ссылка на интерфейс View), а View не знает о Presenter. Это делает Presenter легко тестируемым — можно замокать View.

Когда применять: Толстый клиент с активным UI (Android, десктоп, сложные формы). Когда важна тестируемость UI-логики (Presenter тестируется без браузера/эмулятора).

Когда не применять: В современных веб-фреймворках — React/Vue/Svelte используют компонентную модель, несовместимую с MVP. Простой UI — MVP добавит лишнюю обвязку.

Глава: 8 (Фронтенд-архитектура)


#5.3 MVVM (Model-View-ViewModel)

Описание: Эволюция MVP для data binding. ViewModel — состояние и поведение View без прямой ссылки на View (в отличие от Presenter). Data binding автоматически синхронизирует View и ViewModel через реактивность.

В вебе: Angular (компоненты + binding), Vue (реактивность), Knockout.js. В современных фреймворках MVVM трансформировался в Component-Based Architecture с hooks/effects, но принцип реактивной синхронизации состояния и отображения — тот же.

Когда применять: UI с интенсивным data binding (формы, дашборды, редакторы). Когда нужно разделить UI-логику и отображение для тестирования. Angular, Vue.

Когда не применять: Data binding ведёт к сложно отлаживаемым цепочкам изменений. В React — другая модель (uni-directional data flow), натягивать MVVM на React не стоит. Простой сайт — MVVM избыточен.

Глава: 8 (Фронтенд-архитектура)


#6. Layered Architecture (N-tier, Многослойная архитектура)

Описание: Классическая архитектура, где код организован в горизонтальные слои: Presentation → Business Logic → Data Access → Database. Каждый слой зависит только от нижележащего. Основное правило: слой может общаться только с соседним снизу.

Самый распространённый архитектурный паттерн в вебе — его видел каждый, кто писал на Spring, Django, ASP.NET. Прост в понимании, хорошо знаком большинству разработчиков. Главная проблема — «протекающие слои» (leaky abstraction), когда бизнес-логика просачивается в контроллеры, а SQL — в сервисы.

Когда применять: Стартап / простое приложение — начинай с layered, это проще всего. CRUD-приложения, где логика — это в основном маппинг запросов в данные и обратно. Команда знакома с этим паттерном (а это практически все).

Когда не применять: Сложная бизнес-логика — она «протекает» через все слои. Кодовая база растёт, слои становятся «дырявыми». Хочешь строгую изоляцию доменной логики — Hexagonal/Clean Architecture дадут более чёткие границы. Многослойность начинает тормозить: чтобы добавить одно поле, нужно изменить 4 слоя.

Глава: 11 (Монолит — не грязное слово), 12 (Модульный монолит)


#7. Hexagonal Architecture (Ports & Adapters, Шестиугольная архитектура)

Описание: Alistair Cockburn, начало 2000-х. Идея: ядро приложения (domain logic) не зависит ни от БД, ни от HTTP, ни от UI. Всё, с чем взаимодействует приложение — это «порты» (ports, интерфейсы), а внешние технологии — «адаптеры» (adapters), реализующие эти порты.

Название «шестиугольная» не означает, что сторон должно быть шесть. Это визуализация: ядро в центре, по краям — разные порты, к каждому подключается адаптер. На практике: OrderRepository — порт (интерфейс), PostgresOrderRepository и InMemoryOrderRepository — адаптеры. Ядро не знает, что там за БД.

Когда применять: Сложная бизнес-логика, которую нужно тестировать без инфраструктуры. Приложение с потенциальной сменой БД или внешних сервисов. DDD — Hexagonal это естественный архитектурный стиль для bounded context.

Когда не применять: CRUD-приложение — Hexagonal добавит интерфейсы ради интерфейсов. Никто в команде не понимает паттерн — будет «Hexagonal по имени», где порты лежат рядом с адаптерами и нет реального разделения. Реальной смены технологий не предвидится.

Глава: 4 (DDD), 12 (Модульный монолит)


#8. Clean Architecture (Чистая архитектура)

Описание: Uncle Bob (Robert C. Martin), эволюция Hexagonal + Onion Architecture. Четыре кольца: Entities (самые стабильные) → Use Cases (application logic) → Interface Adapters (контроллеры, презентеры, gateways) → Frameworks & Drivers (БД, веб-фреймворк, UI — самые изменчивые).

Правило зависимости (Dependency Rule): зависимости идут внутрь, от периферии к центру. Внешнее кольцо может зависеть от внутреннего — никогда наоборот. Внутренние кольца не знают о внешних.

На практике используют упрощённую версию, адаптированную под проект. Важнее принцип — бизнес-логика не зависит от инфраструктуры, а не количество колец.

Когда применять: Крупный проект со сложной бизнес-логикой (финтех, healthcare). Система, которая будет жить 5+ лет — инвестиция в архитектуру окупается. Множество внешних зависимостей, которые могут меняться.

Когда не применять: Простое CRUD-приложение или прототип. Стартап на стадии поиска PMF — скорость важнее архитектурной чистоты. Команда не понимает принципы — получится «Clean Architecture по имени» с кучей пустых абстракций. 10 слоёв там, где реально нужно 2-3.

Глава: 3 (Первые принципы архитектуры), 12 (Модульный монолит)


#9. CQRS (Command Query Responsibility Segregation)

Описание: Разделение моделей для записи (commands) и чтения (queries). Команды меняют состояние, но не возвращают данные. Запросы читают данные, но не меняют состояние. Начинается с разделения на уровне одного класса (простой CQRS) и доходит до разделения на уровне БД (full CQRS).

Простой CQRS: метод .createOrder() не возвращает OrderDTO, а возвращает orderId. Метод .getOrder(id) не пишет в БД. Full CQRS: отдельная БД для записи (normalized) и для чтения (read-optimised, denormalized). Синхронизация — через события.

Когда применять: Read и write имеют принципиально разные требования (write: consistency; read: скорость). Один и тот же объект по-разному выглядит при записи и при чтении. Read-запросов на порядки больше, чем write (соцсети, каталоги). Совместно с Event Sourcing.

Когда не применять: Обычный CRUD — разделение команд и запросов просто добавит дублирования. «Мы используем CQRS» как оправдание, что read model и write model синхронизировать не умеем. Нет проблем с производительностью чтения.

Глава: 3 (Первые принципы — CQS), 7 (Data Layer), 17 (Распределённые данные), 20 (Database Scaling — CQRS как стратегия масштабирования чтения)


#10. Event Sourcing (Событийное хранение)

Описание: Храним не текущее состояние, а последовательность событий, которые к нему привели. Вместо UPDATE orders SET status='shipped' сохраняем событие OrderShipped. Текущее состояние — результат применения (replay) всех событий.

Плюсы: полный audit trail, возможность «отмотать» время (time travel), естественная история изменений. Минусы: сложные запросы (нужны проекции), schema evolution событий, объём данных. Часто работает в паре с CQRS: события в event store (write model), read model строит проекции из событий.

Когда применять: Нужен полный audit trail (финтех, compliance, healthcare). Бизнес-логика работает с временными срезами («показать состояние на 1 января»). Конфликты конкурентности — события можно переиграть. Источник правды должен быть immutable.

Когда не применять: Простой CRUD — у тебя и так есть состояние, не надо разлагать его на события. Простые запросы — Event Sourcing их сильно усложняет (нужны проекции, snapshot'ы). Команда не готова к сложности — Event Sourcing — один из самых ментально затратных паттернов.

Глава: 7 (Data Layer), 17 (Распределённые данные)


#11. Saga (Choreography + Orchestration, Сага)

Описание: Паттерн управления распределёнными транзакциями. Вместо двухфазного коммита (2PC) — последовательность локальных транзакций, каждая с компенсирующим действием (compensating transaction) на случай отката. Нет distributed locking — есть eventual consistency.

Два варианта:

Choreography (Хореография): Нет координатора. Каждый сервис реагирует на события и публикует свои. Проще, но логика размазана по сервисам. Сложно понять полную картину. Отладка — просмотр логов всех участников.

Orchestration (Оркестрация): Оркестратор управляет шагами. Знает полную последовательность, вызывает сервисы, обрабатывает ошибки. Сложнее, но контролируемо. Централизованная видимость процесса.

Когда применять: Операция затрагивает несколько сервисов (оформление заказа: резерв → оплата → отправка). Нужна согласованность в конечном счёте (eventual consistency). Невозможна ACID-транзакция из-за разделения данных.

Когда не применять: Операция может быть выполнена в одном сервисе — не распределяй. Нужна сильная согласованность (strong consistency) — пересмотри архитектуру. Компенсирующие транзакции не имеют смысла (отправили письмо — «компенсировать» нельзя). Хореография без мониторинга — сага «висит» и никто не знает.

Глава: 7 (Data Layer), 17 (Распределённые данные — Saga детально)


#12. Transactional Outbox (Транзакционный Outbox)

Описание: Решает проблему: «как гарантированно опубликовать событие, когда меняешь данные в БД?». Без distributed transaction: записываешь и данные, и событие в одну БД, в одной транзакции. Отдельный процесс (poller или CDC) читает outbox-таблицу и публикует события в брокер.

Пример: при создании заказа — вставляешь запись в orders и запись в outbox_events в одной транзакции. Outbox processor читает outbox_events, публикует OrderCreated в Kafka, помечает как отправленное.

Современная реализация: CDC-коннектор (Debezium) читает WAL (Write-Ahead Log) БД и публикует изменения без poller'а и без нагрузки на БД.

Когда применять: Нужно гарантировать доставку событий после изменения данных. Альтернатива distributed transaction (2PC) в микросервисах. Event-driven архитектура с гарантиями доставки. Платёжные системы — потеря события = потеря денег.

Когда не применять: Внутри одного сервиса без внешних потребителей — достаточно синхронного вызова. Потеря события допустима. Команда не готова управлять outbox processor'ом и dead letter queue.

Глава: 7 (Data Layer), 17 (Распределённые данные)


#13. Circuit Breaker (Предохранитель)

Описание: Защищает систему от каскадных отказов. Следит за вызовами к зависимому сервису. Когда ошибки превышают порог — «размыкает цепь» и перестаёт слать запросы на упавший сервис. Вместо этого мгновенно возвращает fallback или ошибку. Через некоторое время пробует снова (half-open state): один тестовый запрос — если успешен, закрывает цепь.

Три состояния: Closed (нормальная работа) → Open (запросы блокируются, возвращается fallback) → Half-Open (пробуем один запрос).

Когда применять: Вызовы к внешним/внутренним сервисам, которые могут упасть или тормозить. Системы с жёсткими latency-SLA — не даём одному медленному сервису убить всю систему (через очередь запросов).

Когда не применять: In-process вызовы без сети — не нужно. Тайм-аута достаточно и он уже настроен. Fallback'а нет и быть не может — circuit breaker только скроет ошибку. Простые системы — timeout + retry может быть достаточно.

Глава: 15 (Микросервисы — Circuit Breaker), 24 (Resilience и Chaos Engineering)


#14. Bulkhead (Перегородка / Изоляция ресурсов)

Описание: Берёт название из кораблестроения: корабль разделён на водонепроницаемые отсеки. Если один отсек затоплен — остальные работают. Изолирует ресурсы системы (connection pools, thread pools) по группам, чтобы отказ в одной группе не убил другую.

Пример: отдельный connection pool для API-запросов (critical) и для background-задач (non-critical). Background-задача зависла — API продолжает работать, потому что у них разные пулы.

Когда применять: Разные типы запросов с разными критичностями (user-facing API + batch jobs). Multi-tenant системы — изоляция одного tenant от другого. Нужно гарантировать, что некритическая операция не съест все ресурсы для критической.

Когда не применять: Нет разных типов запросов — изоляция просто уменьшит утилизацию ресурсов. Стоимость ресурсов критична — Bulkhead снижает эффективность (где-то пулы простаивают). Нет мониторинга пулов — ты не узнаешь, что один отсек «затоплен».

Глава: 15 (Микросервисы — Bulkhead), 24 (Resilience и Chaos Engineering)


#15. Strangler Fig (Фикус-удушитель / Замена по частям)

Описание: Паттерн постепенной замены legacy-системы. Назван в честь фикуса- удушителя (strangler fig), который начинает расти вокруг дерева-хозяина и со временем полностью его замещает.

На практике: рядом с существующей системой строится новая. Трафик постепенно перенаправляется: сначала 10% на новую, потом 50%, потом 100%. Старая система умирает сама, когда весь функционал перенесён. Ключевые элементы: маршрутизатор (router), feature toggle'и для постепенного включения, параллельный запуск.

Когда применять: Миграция legacy-монолита на новую архитектуру. Когда «big bang rewrite» невозможен (а он невозможен в 90% случаев). Постепенная декомпозиция монолита в микросервисы. Системы, которые нельзя остановить на миграцию.

Когда не применять: Нет маршрутизатора (API Gateway, feature flags) — будешь перенаправлять костылями. Legacy-система не поддерживает параллельную работу (нет idempotency, нет API). «Оставим как есть» — дешевле, чем длинная миграция (Strangler Fig — это месяцы/годы).

Глава: 14 (Дорога в распределённый мир), 31 (Эволюция архитектуры)


#16. Sidecar (Боковой контейнер)

Описание: Вспомогательный процесс, запущенный рядом с основным приложением (в одном pod/контейнере). Делят жизненный цикл и сетевое пространство, но работают независимо. Берёт на себя инфраструктурные задачи: проксирование трафика, mTLS, логирование, метрики, обновление сертификатов.

Классическая реализация — service mesh: Envoy или Linkerd-proxy бок о бок с каждым микросервисом. Прокси перехватывает весь сетевой трафик и добавляет наблюдаемость, безопасность, resilience без изменения кода сервиса.

Когда применять: Service mesh (Istio/Linkerd) — sidecar как стандарт деплоя. Добавление infrastructure-функций без изменения кода приложения. Агенты мониторинга, логирования, сбора метрик.

Когда не применять: Функциональность можно реализовать в библиотеке — это проще и без latency overhead. Мало сервисов (< 10) — overhead sidecar'а не оправдан. Каждый sidecar потребляет память и CPU — на масштабе это заметно (особенно Envoy).

Глава: 18 (Service Mesh)


#17. Ambassador (Посредник)

Описание: Похож на Sidecar, но фокусируется на внешних соединениях. Ambassador — прокси между приложением и внешним миром. Отвечает за retry, circuit breaker, rate limiting, аутентификацию для внешних API.

Отличие от Sidecar: Sidecar управляет входящим/исходящим трафиком внутри кластера, Ambassador — только исходящим к внешним системам. Пример: Redis Ambassador, который переключает запросы между мастером и репликами.

Когда применять: Множество внешних зависимостей с разной конфигурацией. Нужно прозрачное переключение между environment'ами (staging → production). Тестирование: ambassador-мок для внешнего API.

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

Глава: 15 (Микросервисы), 18 (Service Mesh)


#18. BFF (Backend for Frontend, Бэкенд для фронтенда)

Описание: Отдельный API-слой (или микросервис) для каждого типа клиента. Mobile BFF, Web BFF, Smart TV BFF — каждый знает особенности своего клиента и возвращает ровно то, что ему нужно.

Проблема, которую решает BFF: универсальный API возвращает или слишком много (mobile платит за трафик), или слишком мало (web приходится делать 5 запросов). BFF — каждому клиенту свой API, оптимизированный под его сценарии.

Классический пример: Spotify — отдельные BFF для десктопа, мобильного приложения и веба. Каждый оптимизирован под свой UI и требования по latency.

Когда применять: Принципиально разные клиенты (web, iOS, Android, Smart TV) с разными требованиями. Mobile: минимизация данных и round trips (экономия трафика и батареи). Web: богатый API с пагинацией и фильтрацией. Разные клиентские команды — каждая владеет своим BFF.

Когда не применять: Один тип клиента — BFF добавит слой без пользы. Клиенты имеют одинаковые требования — GraphQL или единый API проще. Маленькая команда — каждый BFF требует поддержки. Раздувание: N клиентов × N сервисов = N² поддержки.

Глава: 15 (Микросервисы), 6 (API-архитектура)


#19. API Gateway (Шлюз API)

Описание: Единая точка входа для всех клиентов. Принимает запрос, маршрутизирует к нужному микросервису, агрегирует ответы, применяет cross-cutting concerns: аутентификация, rate limiting, логирование, CORS, кэширование, протокольная трансляция (gRPC → REST).

Не путать с BFF: API Gateway обслуживает всех клиентов, а BFF — каждого по-своему. API Gateway — инфраструктурный слой, не содержащий бизнес-логики.

Когда применять: Множество микросервисов (3+), которые нужно скрыть за единым входом. Cross-cutting concerns, вынесенные из сервисов. Агрегация: один запрос → несколько сервисов → один ответ. Протокольная трансляция (gRPC → REST). Упрощение клиента: клиент знает только один адрес.

Когда не применять: Один сервис — API Gateway добавит сетевой hop без пользы. Gateway становится God Object — вся бизнес-логика протекает в него. Gateway как единая точка отказа (SPOF) — делай кластеризацию. «API Gateway всё умеет» — если он знает про бизнес-логику, что-то пошло не так.

Глава: 15 (Микросервисы — API Gateway), 18 (Service Mesh — взаимодействие с API Gateway)


#20. Repository (Репозиторий)

Описание: Прослойка между бизнес-логикой и хранилищем данных. Предоставляет интерфейс для работы с коллекцией объектов: find(), save(), delete(). Выглядит как коллекция в памяти, но за ней — БД, API или файл. Скрывает детали хранения: SQL, ORM, NoSQL API — всё за интерфейсом.

В терминах Hexagonal: Repository — это порт (port) для доступа к данным. Бизнес-логика не знает, что там: PostgreSQL, MongoDB или файл на диске.

Когда применять: Доменная модель с богатой логикой (DDD). Нужно изолировать бизнес-логику от конкретной БД. Хочешь легко тестировать — InMemoryRepository вместо БД. Unit of Work + Repository — стандартная связка.

Когда не применять: CRUD без доменной логики — ORM уже репозиторий, второй уровень абстракции добавит только косвенности. ActiveRecord в Rails — его не оборачивают в Repository, это анти-паттерн. Простой доступ к данным через ORM вполне достаточен.

Глава: 4 (DDD), 7 (Data Layer), 12 (Модульный монолит)


#21. Unit of Work (Единица работы / UoW)

Описание: Координирует запись изменений в рамках одной бизнес-операции. Отслеживает, какие объекты были изменены, и в один момент (commit) записывает все изменения. Если что-то пошло не так — rollback. «Я изменю три объекта, а ты запиши всё разом, когда я скажу».

В вебе: сессия Hibernate, EntityManager в JPA, DbContext в Entity Framework, транзакция Spring + JPA. Когда ты открываешь транзакцию и работаешь с несколькими репозиториями — это Unit of Work.

Когда применять: Одна операция изменяет несколько объектов в БД. Нужна гарантия атомарности изменений. Используешь ORM (JPA/Hibernate, Entity Framework, SQLAlchemy) — UoW уже встроен.

Когда не применять: Простая операция с одним изменением — транзакция на уровне БД справится. Eventual consistency — не нужна атомарность. NoSQL без транзакций — UoW там не работает.

Глава: 4 (DDD), 7 (Data Layer)


#22. Specification (Спецификация)

Описание: Инкапсулирует бизнес-правило (условие отбора) в объект. Вместо того чтобы размазывать условие where status = 'active' AND createdAt > now() - 30d по всем репозиториям, создаёшь new ActiveUsersSpecification(). Комбинируется через .and(), .or(), .not().

В DDD — явное выражение бизнес-правила в коде. Репозиторий принимает Specification и преобразует в query (SQL, LINQ, Criteria API).

Когда применять: Много бизнес-правил отбора, которые меняются. Нужно переиспользовать условия между разными репозиториями. Бизнес-логика отбора сложная и не помещается в один where. Хочешь явно описать доменное правило в коде.

Когда не применять: Одно-два простых условия — передай их прямо в репозиторий. Правила меняются не бизнесом, а производительностью (Specification не про SQL-оптимизацию). ORM даёт query builder — Specification не нужен. Правило никогда не переиспользуется.

Глава: 4 (DDD — бизнес-правила и инкапсуляция), 7 (Data Layer)


#23. Domain Event (Доменное событие)

Описание: Фиксирует значимое событие в домене. Не техническое (не «запрос получен», не «тайм-аут»), а бизнесовое: OrderPlaced, PaymentReceived, UserRegistered. Называется термином бизнеса, не разработчика — часть ubiquitous language.

В DDD: агрегат публикует Domain Event при изменении состояния. Другие агрегаты (или сайд-эффекты) реагируют: отправить email, обновить скоринг, изменить другой агрегат, запустить сагу.

Когда применять: Бизнес-логика содержит «когда X произошло, сделай Y». Разные части домена (bounded contexts) должны общаться через события. Audit trail естественным образом. Event-driven архитектура на уровне бизнес-логики.

Когда не применять: «Событие ради события» — если на него никто не реагирует, это просто логирование. Доменное событие совпадает с техническим: UserUpdated ничего не говорит о домене, UserEmailChanged — говорит. Событие используется только для логирования — это не Domain Event, это audit log.

Глава: 4 (DDD — Domain Events), 16 (Event-Driven Architecture — где Domain Events переходят в инфраструктурные события)


#24. Process Manager / Saga Orchestrator (Менеджер процессов)

Описание: Центральный координатор распределённой бизнес-операции (саги). Получает события, принимает решения, отправляет команды. Отслеживает состояние процесса и управляет компенсациями при ошибках.

Отличие от Saga Orchestrator: Process Manager может принимать решение на основе внешних сигналов (таймеры, события, ответы от людей). Хранит состояние процесса (часто как state machine). Умеет ждать: «если через 24 часа оплата не пришла, отмени заказ». Реализации: Temporal, Camunda, AWS Step Functions.

Когда применять: Длинно-живущая бизнес-операция (days/weeks — ожидание оплаты, прохождение compliance). Операция требует человеческого решения (approval workflow). Нужна централизованная видимость процесса. Журналирование и replay: Process Manager может переиграть процесс на тестовых данных.

Когда не применять: Операция короткая и простая — choreography saga проще. Process Manager становится God Class со всей бизнес-логикой. Процесс никогда не меняется — зачем его централизовать? Процесс без пауз (sequence sync calls) — не нужно долгоживущее состояние.

Глава: 17 (Распределённые данные — Saga Orchestration), 22 (Асинхронность и очереди — Temporal, Camunda, AWS Step Functions)


#Сводная таблица

№ Паттерн Категория Контекст Главы
1.1 Singleton Порождающий DI, кэши, пулы 3, 12
1.2 Factory Порождающий DI-контейнеры, инфраструктура 3
1.3 Abstract Factory Порождающий Семейства объектов (БД, облака) 3
1.4 Builder Порождающий Сложные объекты, конфигурация 3
2.1 Adapter Структурный Интеграция, Hexagonal 6, 12, 18
2.2 Facade Структурный API, модули 12, 15
2.3 Proxy Структурный Кэш, lazy, логирование 15, 18, 21
3.1 Observer Поведенческий In-process события 4, 16
3.2 Pub/Sub Поведенческий Event-driven, очереди 16, 22
4.1 Strategy Поведенческий Алгоритмы, провайдеры 9, 21, 24
4.2 Template Method Поведенческий CI/CD, фреймворки 6, 13
5.1 MVC Архитектурный UI Server-rendered веб 2, 8
5.2 MVP Архитектурный UI Android, thick clients 8
5.3 MVVM Архитектурный UI Angular, Vue, data binding 8
6 Layered Architecture Архитектурный Простые системы, CRUD 11, 12
7 Hexagonal Architecture Архитектурный DDD, сложный домен 4, 12
8 Clean Architecture Архитектурный Enterprise, долгий lifecycle 3, 12
9 CQRS Data Разделение read/write 3, 7, 17, 20
10 Event Sourcing Data Audit, time travel 7, 17
11 Saga Data Распределённые транзакции 7, 17
12 Transactional Outbox Data Гарантированная доставка событий 7, 17
13 Circuit Breaker Инфраструктурный Resilience, защита 15, 24
14 Bulkhead Инфраструктурный Изоляция ресурсов 15, 24
15 Strangler Fig Инфраструктурный Миграция legacy 14, 31
16 Sidecar Инфраструктурный Service Mesh 18
17 Ambassador Инфраструктурный Внешние соединения 15, 18
18 BFF Инфраструктурный Разные клиенты 15, 6
19 API Gateway Инфраструктурный Микросервисы 15, 18
20 Repository DDD Data access 4, 7, 12
21 Unit of Work DDD Транзакции изменений 4, 7
22 Specification DDD Бизнес-правила 4, 7
23 Domain Event DDD Бизнес-события 4, 16
24 Process Manager DDD / Workflow Долгие процессы 17, 22

#Как пользоваться этим справочником

Этот аппендикс — шпаргалка, а не учебник. Если паттерн незнаком — прочитай соответствующую главу книги. Если знаком — сверься, когда его применять, а когда — бежать без оглядки.

Главное предупреждение: самый опасный паттерн — «в руках молотка всё выглядит как гвоздь». Если ты только что прочитал про новый паттерн и видишь его применение везде — остановись. Спектр архитектурной зрелости: от простого к сложному. Не усложняй раньше времени.

Связь с другими аппендиксами: