Домены и команды

·5 мин чтения·Обновлено

Bounded Context: почему границы бизнеса должны появляться в архитектуре

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

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

Здесь нужен не ещё один универсальный статус, а уточнение моделей. Bounded Context — граница, внутри которой термины и правила согласованы. За её пределами тот же человек или организация могут участвовать в другой модели. Различия надо переводить осмысленно, а не прятать в общем объекте с постоянно растущим набором исключений.

Одна организация, несколько разных вопросов

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

Один покупатель может платить за несколько подразделений, а пользователь продукта вообще не быть плательщиком. Поэтому связь между идентификаторами не всегда будет один к одному. Присвоить общий номер полезно для сопоставления, но он не устраняет разницу ролей и правил.

В описании Bounded Context у Мартина Фаулера именно различия моделей и языка объясняют необходимость явных границ. Это не предложение запретить общие справочники. Достаточно не заставлять один объект отвечать на вопросы, для которых у него нет единого смысла.

Граница модели не обязана совпадать с отделом или сервисом

Бухгалтерия как подразделение — ещё не готовый контекст. Внутри неё могут существовать разные правила выставления счетов и расчёта вознаграждений. А одна модель иногда используется сотрудниками нескольких отделов. Организационная схема помогает найти людей для разговора, но не заменяет изучения работы.

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

Bounded Context отличается и от микросервиса. Первый ограничивает модель, второй — отдельно поставляемую техническую часть. Контекст можно реализовать внутри модульного монолита; он может включать несколько компонентов. Само появление сети между ними хороших смысловых границ не создаёт. Связь анализа предметной области с выбором сервисов разобрана в Azure Architecture Center.

Как передать факт, не передавая соседу все свои правила

Вернёмся к клиенту. Система расчётов может сообщить о наступившем ограничении на новые коммерческие обязательства. Продажи используют этот факт по согласованному правилу. Поддержке не нужно автоматически отключать учётные записи: ей требуется понять, какие действующие услуги действительно затронуты.

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

Иногда внешняя система отдаёт только неудобный общий статус. На границе можно переводить его в понятия собственной модели, не распространяя чужие особенности по всему коду. Этот подход известен как Anti-Corruption Layer. Перевод должен сохранять смысл; переименовать blocked в isAllowed и потерять основание ограничения недостаточно.

Кто имеет право менять конкретный факт

Вместо общего спора «кто владелец клиента» полезнее перечислить факты. Кто подтверждает погашение задолженности? Кто назначает пользователя организации? Кто определяет действительность подписки? Ответственный за один факт не получает автоматически право редактировать всё, что известно об участнике.

Физически данные могут пока оставаться в одной базе. Существеннее запрет на неоговорённую запись в чужую область. Если продажи обходят расчёты и напрямую исправляют признак долга, граница существует только на диаграмме. Переезд на разные серверы перенесёт тот же конфликт в API.

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

Независимые модели не разрешают противоречивые обещания

Если продажи обязаны проверить финансовое ограничение до подтверждения сделки, нужно определить допустимую свежесть сведений. Асинхронное сообщение может отставать. В зависимости от риска потребуются проверка у источника, предварительное состояние сделки или другой согласованный механизм. Слово «контекст» не выбирает его автоматически.

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

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

Проверить границу на следующем изменении

Возьмите несколько недавних задач и отметьте, какие правила действительно пришлось менять вместе. Затем рассмотрите новый вариант: например, один плательщик получает право обслуживать несколько независимых организаций. Где потребуется изменить модель, какие факты передать соседям и какие прежние операции должны остаться без изменений?

Если небольшая поправка требует синхронного выпуска всех частей, границу стоит пересмотреть. Иногда она слишком мелкая; иногда общий объект продолжает связывать формально разделённые модули. Исправить это внутри монолита может быть дешевле, чем сразу выносить сервисы.

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