30 апр. 2025 г.·7 мин чтения

Когда не стоит разделять ограниченный контекст из‑за общей таблицы

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

Когда не стоит разделять ограниченный контекст из‑за общей таблицы

Почему общие таблицы вводят людей в заблуждение

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

Иногда это действительно так. Часто — нет.

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

Организационные схемы усложняют ситуацию. Одна команда отвечает за оформление заказа, другая — за возвраты, третья — за финансовую отчётность. Со временем софт начинает зеркалить структуру компании вместо бизнеса. Тогда разделение кажется очевидным, потому что разные команды трогают одни и те же данные. Но разные команды не всегда означают разные домены. Иногда это просто разные группы, работающие с одними и теми же правилами под разными углами.

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

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

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

Общая таблица — это не граница

Таблица показывает, где лежат данные. Она не говорит, кто отвечает за смысл этих данных.

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

Начните с полей, а не со схемы. Спросите, что значит каждое поле, кто может его менять и какое правило решает, допустима ли смена. Если поля вроде "refund_status", "approved_by" и "refund_reason" все подчиняются одной и той же политике поддержки, работа с возвратами, вероятно, всё ещё принадлежит операциям с заказами, даже если позже финансы читают ту же таблицу.

Язык бизнеса обычно яснее структуры базы. Если две группы описывают работу одними и теми же словами, спорят об одних и тех же исключениях и следуют одному пути согласования, они, вероятно, внутри одного контекста. Разделите их слишком рано — и обычно получите дублирующиеся правила, задания синхронизации и баги, проявляющиеся в двух местах одновременно.

Реальное разделение проявляется в поведении, а не в хранении. Вы должны увидеть такие различия:

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

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

Это часто встречается в старых системах стартапов. Команда видит заказы и возвраты в одной переполненной таблице и хочет аккуратное разделение. Но если одни и те же люди обрабатывают оба процесса, одна и та же политика решает за оба, и одна и та же временная шкала объясняет оба — это одна бизнес‑работа в неудобном хранилище. Сначала почистите модель. Разделяйте позже, когда бизнес действительно разделится.

Признаки, что один домен всё ещё владеет правилами

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

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

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

Несколько подсказок обычно появляются вместе. Те же люди утверждают изменения в обоих наборах правил. Команды правят одни и те же поля в одном релизе. Одна группа обрабатывает исключения для обеих областей. Сотрудники используют одно и то же бизнес‑название для всего процесса, а не называют две отдельные возможности.

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

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

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

Как выглядит реальное разделение

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

Самый явный признак — независимые правила. Одна сторона может поменять свою логику, не втягивая другую. Если биллинг меняет правила просрочек, поддержке не нужно переписывать свои процессы. Если поддержка меняет способ проверки аккаунта перед его повторным открытием, биллинг продолжит работать как обычно. Такую свободу трудно симулировать.

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

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

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

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

Практическая проверка перед разделением

Сначала почистите
Разберите общие таблицы аккуратно, не торопясь с дублированием логики и синхронизирующими заданиями.

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

Запишите реальные решения, которые люди принимают на основе этой таблицы. Будьте конкретны. «Можно ли вернуть этот заказ?» и «Показывать ли этот заказ в портале клиента?» — разные решения, но они могут зависеть от одних и тех же бизнес‑правил.

Простая проверка обычно работает:

  1. Перечислите ежедневные решения, которые поддерживает таблица.
  2. Отметьте правила, которые склонны меняться вместе.
  3. Заметьте, кто утверждает эти изменения и кто разбирается с последствиями.
  4. Назовите точную передачу, где одна сторона передаёт факты другой.
  5. Отложите разделение, если эта передача всё ещё звучит расплывчато.

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

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

Самый ясный сигнал — передача. Реальное разделение появляется, когда одна сторона может закончить свою работу и передать факты, а не недоделанные решения, другой стороне. Один домен может сказать: «Платёж зафиксирован в 10:32, сумма $84, способ — карта». Другой домен тогда применяет свои правила, не заглядывая во внутренности первого домена.

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

Заказы и возвраты

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

Такой запрос логичен с точки зрения рабочего процесса команды. Но это не обязательно оправдано с точки зрения доменной модели.

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

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

Это тот паттерн, за которым нужно следить. Две команды могут трогать одни и те же данные, но один домен всё ещё владеет правилами.

Быстрый тест — задать несколько прямых вопросов. Может ли команда возвратов утверждать или отклонять возвраты без проверки состояния заказа и платежа? Может ли политика заказов измениться без принуждения к изменению правил возврата? Можете ли вы определить «возврат завершён» без повторного использования терминов заказа, налога и платежа?

Если в основном ответ — «нет», скорее всего у вас одна граница с разными ролями внутри неё, а не два отдельных домена.

Отдельный контекст Refunds становится оправданным, только когда у возвратов появляются собственные политики, язык и жизненный цикл. Маркетплейс — хороший пример. Там возвраты превращаются в формальный процесс претензий с окнами для споров, доказательной базой, правилами дебетования продавца и внешним возвратом средств. Это другое.

До тех пор держите модель вместе. Пусть поддержка владеет экраном, если нужно, но не путайте владение экраном с бизнес‑владением.

Ошибки, создающие фальшивые границы

Сделайте границы ясными
Переведите размытое владение в чёткие доменные правила, которые команда сможет объяснить и поддерживать.

Фальшивые границы обычно появляются, когда люди реагируют на реальную боль, не связанную с самой моделью. Две команды спорят из‑за таблицы — и разделяют домен. Запрос отчётности растёт — и вокруг аналитики придумывают новый контекст. Код выглядит старым и запутанным — и переименование модуля считают достаточной поделкой.

Такой шаг часто делает всё хуже. Таблица остаётся общей, правила перемешаны, а система приобретает лишние API, задания синхронизации и новые места для багов.

Структура команды вызывает много неверных разделений. Если sales ops и finance оба трогают одну и ту же запись клиента, это не значит, что бизнес делится на два домена. Возможно, обе команды просто нуждаются в одних и тех же данных по разным причинам. Организационные схемы меняются иногда каждый год. Бизнес‑правила обычно — нет.

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

Это встречается в быстрорастущих стартапах. Кто‑то копирует пример из учебника и пытается втиснуть его в бизнес, который работает иначе. Результат выглядит аккуратно на диаграммах и неудобно в реальности.

Быстрые проверки перед тем, как провести линию

Уточните владение контекстом
Составьте карту правил, передач и владения до того, как архитектурный дрейф превратится в переработку.

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

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

Начните с принятия решений. Если люди с одной стороны всё ещё должны читать правила другой стороны, прежде чем действовать, у вас нет чистого разделения. У вас один домен с дополнительными шагами.

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

Посмотрите на восприятие клиента. Люди видят это как две отдельные услуги с разными целями или как один поток с несколькими экранами? Клиенты быстро выявляют фальшивые границы.

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

Полезный мыслительный эксперимент прост: если завтра вы объединили команды, осталась бы граница естественной, или все тихо вернулись бы к одному подходу? Этот вопрос часто честнее, чем дизайн‑воркшоп.

Это ещё важнее в небольших командах. Разделение, которое выглядит красиво на доске, может превратиться в ежедневные согласования, дублированные тесты и трение при релизах. Oleg Sotnikov часто видит это в работе со стартапами: команды разделяются слишком рано и потом тратят больше времени на перевод правил, чем на продукт.

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

Что делать в запутанной системе

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

Часто это самый быстрый способ понять, когда не стоит разделять bounded context. Две команды могут трогать одни и те же данные, но это не значит, что они владеют разными доменами. Иногда одна область всё ещё принимает реальные решения, а остальная система только реагирует.

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

Держите обзор простым. Проследите жизненный цикл одной записи, а не всей системы. Отметьте каждое правило, утверждение, исключение и изменение статуса. Запишите, кто на практике владеет каждым решением. Держите контекст целым, пока не сможете назвать чистое событие, которое передаёт контроль кому‑то другому.

Это событие важно. Если вы не можете указать что‑то ясное вроде «возврат утверждён», «счёт выставлен» или «отправление отправлено», разделение, вероятно, всё ещё расплывчато. Граница вокруг общей таблицы становится реальной, когда бизнес‑владение меняется в конкретный момент, а не тогда, когда кодовая база кажется переполненной.

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

Если нужен второй взгляд, Oleg Sotnikov на oleg.is работает как Fractional CTO и помогает стартапам разобраться с архитектурой и вопросами владения. Польза не в диаграмме, а в поиске границы, которую вся команда сможет объяснить, не открывая определения таблицы.