Когда все уровни контекста смешаны
Что мешает увидеть общую картину, когда все детали доступны одновременно?
Обычный репозиторий не разделяет сведения по масштабу: бизнес-области, операции, модели данных, порядок вызовов, инфраструктура и конкретные строки кода представлены одновременно. Рабочей памяти приходится удерживать факты разного уровня и самостоятельно восстанавливать отношения между ними. Внимание постоянно переключается между устройством системы и локальными деталями, поэтому понимание быстро рассыпается после перерыва.
Как отсутствие общей картины влияет на работу
Ниже один и тот же набор сведений показан в двух состояниях: слева они смешаны, справа выстроены в пять последовательных вопросов. Начнём с первого: где в системе живёт ответственность?
Сначала — карта ответственности
Где живёт ответственность?
Первой опорой становится карта ответственности. Она собирает контроллеры, сервисы, модели данных, инфраструктурные адаптеры и цепочки вызовов вокруг крупных областей системы — каркаса, к которому затем можно привязывать операции, данные и код.
Домены делят систему не по техническим слоям, а по устойчивым областям ответственности: заказы, платежи, коммуникации, аналитика. Вместо сотен равноправных файлов появляется первая обозримая топология.
Что даёт карта доменов
На схеме четыре домена образуют верхний уровень приложения. Дальше мы будем последовательно раскрывать StoreDomain: сначала увидим его действия, затем контракт одной операции, её сценарий и конкретную реализацию.
StoreDomainОтвечает за корзину, заказ и передачу в доставку
BillingDomainОтвечает за платежи, счета и возвраты
MessagingDomainОтвечает за коммуникации с клиентом и вебхуки
AnalyticsDomainОтвечает за события, витрины и бизнес-отчётность
Карта превращается в каталог возможностей
Что умеет система?
Карта доменов показывает, где находится ответственность, но пока не говорит, что система умеет делать. Для этого каждый домен раскрывается как каталог действий — именованных возможностей, которые он предоставляет остальной системе.
Action — именованная публичная возможность домена. Каталог показывает не внутренние функции, а операции, которые домен предоставляет остальной системе, и направленные связи между ними. Каждое действие становится единой точкой обращения: вызывающая сторона выбирает нужную возможность по её смыслу, не собирая операцию из отдельных методов.
Что даёт каталог действий
На схеме выделен CreateOrderAction — действие, которое запускает создание заказа. Рядом показаны другие действия StoreDomain и связи между ними. Одна операция может опираться на другую, но зависимости направлены и не замыкаются в цикл. На этом уровне видны только имена действий и их связи; входные данные, результат, сценарий и код будут раскрыты дальше.
CreateOrderActionСоздать заказ: проверить, зарезервировать и оплатить
→ ChargePaymentAction
GetOrderActionПолучить актуальное состояние заказа
CancelOrderActionОтменить заказ и запустить возврат
→ RefundPaymentAction
ShipOrderActionПередать подтверждённый заказ в доставку
Фиксируем границу операции
Что операция требует и обещает?
У возможности уже есть имя и место в системе. Чтобы использовать её как «чёрный ящик», нужно точно знать, какие данные она принимает и какой результат обязана вернуть.
Contract делает границу Action типизированной и однозначной. Params описывает всё, что операция принимает, Result — всё, что она обязана вернуть. Вызывающий код зависит от этого обещания, а не от устройства Action внутри. Реализацию можно менять, пока вход, выход и наблюдаемое поведение сохраняют совместимость.
Что даёт контракт действия
У знакомого CreateOrderAction появляется полная сигнатура: слева CreateOrderParams, справа CreateOrderResult. Поля больше не существуют как абстрактные модели данных — они относятся к конкретной операции с понятным местом и назначением. Внутренность Action по-прежнему не требуется для его использования.
CreateOrderParamsitems: list[Item]
currency: str
CreateOrderActionОркестрировать создание заказа за одной объявленной границей
CreateOrderResultpayment_id: str
status: OrderStatus
Разворачиваем операцию в сценарий
Как развивается сценарий?
Контракт фиксирует начало и конец операции, но не показывает, как одно превращается в другое. Для этого раскрываем внутренний ход бизнес-сценария.
Pipeline делает основной бизнес-сценарий линейным и видимым: проверить вход, зарезервировать товар, провести оплату, собрать результат. Это не означает, что в реальности нет ошибок, развилок и компенсаций; они получают явное место относительно основной линии. Каждый шаг тоже имеет локальный контракт: объявляет, что читает из Params, State и Context, и что добавляет в State для следующих этапов.
Что даёт сценарий операции
Домен дал сценарию место, Action — имя, Contract — начало и обещанный итог. Pipeline добавляет причинный порядок и внутренние границы. Шаг reserve_inventory выделен как отдельное изменение состояния: он получает уже проверенные данные и оставляет reservation_id для продолжения сценария.
Только теперь — конкретное поведение
Где находится конкретное поведение?
Pipeline показывает точное место нужного поведения и резко сужает область поиска. Теперь можно открыть не весь репозиторий и даже не весь Action, а реализацию одного шага с уже известной целью, входом и выходом.
Code становится пятым уровнем не потому, что детали не важны, а потому, что теперь они окружены смыслом. Уже известно, какому домену принадлежит поведение, какую возможность реализует Action, что обещает Contract и какое место занимает reserve_inventory в Pipeline. Реализация читается как локальный ответ на конкретную задачу, а не как вход в бесконечное расследование репозитория.
Что даёт изоляция поведения в отдельном шаге
Открывая reserve_inventory, мы заранее знаем его намерение, входы и место в сценарии. Принцип остаётся тем же: внешние эффекты должны проходить через объявленные Resource и публичные Action. Архитектурная грамматика делает отклонения видимыми и проверяемыми, не притворяясь, что один только текст описания уже физически запрещает любой обход.
$ uv run python store/actions/create_order.pyПять уровней не прячут код и не упрощают систему до схемы. Они сохраняют путь от общей модели к детали. Новичок постепенно строит контекст, архитектор управляет грамматикой и границами вместо каждого файла, а AI-агент выполняет локальную работу внутри заданных правил: человек проектирует язык системы, машина действует на этом языке.
