# 05. Декомпозиция системы

Как резать систему по ответственностям, отличать хорошие границы от случайных папок и использовать cohesion, coupling и bounded context на практике.

- **Author:** Фёдор Чищин
- **Level:** advanced
- **Reading time:** ~25 минут чтения
- **Published:** 2026-05-23
- **Source:** https://fedorthinks.com/ru/learn/software-architect-05-decomposition

---

## 1. Главная идея

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

### Декомпозиция начинается с причин изменения

> Если одну дверь постоянно двигают из-за склада, а другую из-за входа для гостей, это разные зоны здания. Их не нужно проектировать как одну стену.

Компонент с **high cohesion** содержит вещи, которые меняются по одной причине. Компонент с **low coupling** мало знает о соседях и общается через понятный контракт. Эти два свойства важнее названий паттернов.

Плохая декомпозиция часто выглядит аккуратно в IDE: `controllers`, `services`, `repositories`, `utils`. Но если маленькая продуктовая правка требует менять пять слоёв и три домена, система всё равно плохо разрезана. Хорошая декомпозиция позволяет изменить checkout, billing или identity без мысленной загрузки всего продукта.

### Граница — это ещё и ownership

> Карта города бесполезна, если никто не знает, кто чинит мосты, кто отвечает за светофоры и кому звонить при аварии.

Архитектурная граница должна иметь владельца. Если модуль «общий», но меняют его все, он быстро становится зоной риска. Если bounded context принадлежит команде, у неё появляется право менять внутреннюю модель и обязанность держать внешний контракт стабильным.

Поэтому decompositon и team topology связаны. Иногда правильный вопрос звучит не «какой сервис выделить», а «какая команда должна владеть этим потоком end-to-end».

## 2. Пример и антипример

Один и тот же домен можно разрезать по таблицам, слоям или бизнес-потокам. Работает обычно третий вариант.

### Пример: checkout как вертикальный slice

> Касса в магазине отвечает за путь покупки: корзина, цена, оплата, чек. Она не является «слоем кнопок» или «слоем SQL».

В e-commerce checkout может владеть pricing snapshot, payment intent, order draft и failure handling. Catalog остаётся владельцем товаров, identity — пользователей, warehouse — остатков. Checkout не копирует чужую логику, а запрашивает данные через контракты и публикует событие `OrderPlaced`.

Такой vertical slice удобен: команда понимает пользовательский поток целиком, а изменения в оплате не расползаются по всем подсистемам.

### Антипример: декомпозиция по техническим слоям как единственная граница

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

Система разделена на `user-service`, `order-service`, `payment-service`, но внутри каждого сервиса есть общий `common-domain`, общая база и shared validators. Формально сервисы есть, фактически границ нет.

Ещё хуже, когда команды владеют слоями: frontend team, backend team, database team. Любая фича становится проектом координации. Это увеличивает lead time и cognitive load.

#### Самопроверка

- Что является причиной изменения этого модуля?
- Может ли команда изменить его без согласования с пятью соседями?
- Есть ли у границы владелец?
- Какие данные и инварианты действительно принадлежат этому контексту?

Следующий модуль: [Слои и зависимости](./software-architect-06-layers).
