Subdomain и Bounded Context: как не перепутать границы

Из статьи вы поймёте разницу между Subdomain и Bounded Context и получите практический способ проверить границы моделей в своём проекте.
Subdomain и Bounded Context легко перепутать: оба понятия описывают границы, часто получают одинаковые названия и выглядят на схемах как одинаковые прямоугольники. Поэтому сложно понять, где заканчивается часть бизнеса и начинается архитектурное решение.
Путаница становится практической проблемой, к примеру, когда «Заказы» обозначают одновременно бизнес-процесс, модуль, таблицу и будущий микросервис. Команда делит систему по структуре кода и протаскивает одну модель туда, где одинаковые термины имеют разные значения.
Из статьи вы поймёте разницу между Subdomain и Bounded Context и получите способ проверить границы моделей в своём проекте.

Поддомены и контексты описывают разные области

Subdomain. Часть бизнеса с собственной задачей и правилами. Для платформы доставки это может быть приём заказов, назначение курьеров или расчёт выплат. Поддомен существует независимо от архитектуры: после замены монолита сервисами бизнес-задача остаётся.
Bounded Context. Явная граница, внутри которой термины и правила модели имеют согласованное значение. Это проектное решение. Контекст можно реализовать модулем монолита, отдельным сервисом или несколькими компонентами под общим владением. Отдельная база данных не обязательна.
Соответствие поддоменов и Bounded Context в продуктовой организации
Поддомены описывают бизнес, Bounded Context — границы моделей. Основной ориентир — соответствие 1:1.
Верхняя часть схемы описывает бизнес, нижняя — границы моделей в программном решении.

Один термин, разные модели

Один объект можно моделировать по-разному, если меняются цели и правила. Для бухгалтерии сотрудник получает зарплату, для службы безопасности — имеет права доступа. Обе модели называются Employee и используют один Id, но содержат разные данные и поведение.
Один человек и две модели Employee в контекстах Payroll и Access Control
Одинаковый идентификатор связывает данные, но правила и модели остаются разными.
Без контекстов. Команда получила бы общий Employee с зарплатой, бонусом, признаком активности, уровнем доступа и сроком действия пропуска. Часть полей не нужна каждому сценарию, а изменение правил безопасности заставляет проверять код расчёта выплат. Похожие признаки IsActive и IsSuspended описывают разные причины, но в общей модели легко начинают влиять друг на друга.
Вот модель Employee в контексте Payroll. Она хранит только состояние, которое влияет на выплату: оклад, бонус и признак действующего трудового договора.
namespace Payroll; public sealed record Employee( Guid Id, decimal MonthlySalary, decimal MonthlyBonus, bool IsActive) { public decimal CalculateMonthlyPay() { if (!IsActive) { return 0m; } return MonthlySalary + MonthlyBonus; } }
Метод отвечает на один вопрос Payroll: сколько начислить сотруднику за месяц.
А это Employee в контексте Access Control. Здесь важны уровень доступа, блокировка пропуска и срок его действия.
namespace AccessControl; public enum AccessLevel { Office, ServerRoom } public sealed record Employee( Guid Id, AccessLevel Level, bool IsSuspended, DateTime AccessValidUntil) { public bool CanEnterServerRoom(DateTime now) { return !IsSuspended && Level == AccessLevel.ServerRoom && now <= AccessValidUntil; } }
Метод отвечает на вопрос Access Control: можно ли пропустить сотрудника в серверную сейчас. Payroll не зависит от правил пропуска, а Access Control — от формулы начисления. При обмене контексты передают Id и необходимые факты, а не общий класс Employee.

Поддомены обнаруживают, контексты проектируют

Поддомены ищут через бизнес-цели, решения, правила, события и конфликты терминов. Признаки границы:
  • меняется бизнес-цель;
  • меняются эксперты и владельцы правил;
  • то же слово получает другой смысл;
  • у процесса свой ритм изменений и ограничения;
  • события образуют отдельный связный процесс.
Интервью, пользовательские сценарии и Event Storming дают гипотезу о поддоменах, которую проверяют с экспертами. Результат — карта бизнес-возможностей, а не список сервисов.
Процесс от исследования бизнеса к проектированию Bounded Context
Границы поддоменов находят в бизнесе, границы контекстов проектируют в решении.
Затем команда проектирует Bounded Context с учётом продуктовых команд, транзакций и стоимости интеграции. Хорошая граница сохраняет модель согласованной, а большинство изменений — локальными.

Соответствие 1:1 как рабочая гипотеза

В современной практике поддомен и Bounded Context чаще соответствуют друг другу 1:1. Компания делится на продуктовые команды, и каждая команда отвечает за бизнес-возможность, её модель, данные и контракты. Поэтому граница модели естественно следует за границей ответственности команды.
Один поддомен всё же может поддерживаться несколькими контекстами. Это оправдано, если внутри него есть модели с разными правилами, экспертами, жизненными циклами или требованиями к согласованности.
Современное соответствие поддомена и Bounded Context
В продуктовой организации основной вариант — 1:1. Несколько контекстов нужны для действительно разных моделей.
Такое разделение увеличивает число интеграций и переводов между моделями. Поэтому начинайте с 1:1, а несколько контекстов внутри поддомена вводите только для явно различающихся моделей. На карте фиксируйте поддомен, контексты, команды-владельцы и контракты между ними.

Практический алгоритм выделения границ

  1. Определите домен и цель системы. «Система заказов» слишком узка, если продукт управляет всей доставкой.
  2. Соберите бизнес-сценарии, события, решения и правила.
  3. Сгруппируйте связанные возможности в поддомены и проверьте их с экспертами.
  4. Отметьте слова с несколькими значениями. «Заказ» для продавца, курьера и бухгалтера может требовать разных моделей.
  5. Предложите Bounded Context для каждой модели. Начните с 1:1, затем учтите команды, транзакции и частоту изменений.
  6. Зафиксируйте события, API, владельцев контрактов и правила перевода данных на Context Map.
  7. Проверьте границы на недавнем требовании. Если небольшое изменение проходит через всю систему, границы стоит пересмотреть.
Не обязательно сразу создавать микросервисы. В монолите можно разделить пространства имён, модели, схемы данных и зависимости. Это даст обратную связь дешевле, чем раннее физическое разделение.

Итоги

  • Subdomain описывает часть бизнеса, а Bounded Context — границу модели в программном решении.
  • Поддомены обнаруживают вместе с экспертами, контексты проектируют.
  • Начинайте с соответствия 1:1 и проверяйте границы на реальных изменениях.