Короткий ответ
Можно либо укрепить границы между Django apps внутри того же монолита (чёткие интерфейсы между приложениями, запрет прямых импортов моделей друг друга, явные доменные API), либо выделить наиболее независимую и нагруженную часть в отдельный сервис; выбор зависит от того, где именно боль — в связанности кода (решается рефакторингом границ) или в операционных ограничениях монолита (деплой, масштабирование, разные команды — тогда обоснован отдельный сервис).
Как это работает подробнее
Монолит с плохо определёнными границами между apps часто страдает от того, что модели/бизнес-логика одного app напрямую импортируются и используются в другом, создавая неявные циклические зависимости — любое изменение рискует задеть много мест. Укрепление границ (например, через выделенные сервисные функции/слой «публичного API» app, запрет прямого доступа к internal-моделям других apps) снижает связанность без немедленного выделения в отдельный сервис и без накладных расходов на сетевое взаимодействие.
Укрепление границ внутри монолита дешевле и безопаснее (нет распределённых транзакций и сетевых отказов), но не решает операционные проблемы отдельного масштабирования/деплоя конкретной части. Выделение в отдельный сервис даёт независимость деплоя и масштабирования, но добавляет сложность согласованности данных, сетевых отказов и эксплуатации ещё одного сервиса. Критерии выбора — реальная причина боли (связанность кода vs операционные ограничения), зрелость команды в распределённых системах и готовность нести дополнительную инфраструктурную сложность.
Пример кода
Признаки, что проблема в связанности кода (решать рефакторингом границ):
- Любое изменение в одном app требует правок в нескольких других.
- Модели одного app напрямую импортируются и изменяются в другом app.
Признаки, что нужен отдельный сервис (операционная граница):
- Часть функциональности требует отдельного масштабирования под нагрузку,
несвязанную с остальным монолитом (например, обработка файлов vs обычные CRUD-страницы).
- Над этой частью хочет работать отдельная команда с собственным релизным циклом.
Первый шаг в любом случае - явно выделить "публичный" интерфейс app
(функции/сервисный слой), через который с ним взаимодействуют остальные,
не трогая его внутренние модели напрямую.Что использовать на практике
- Практика. Выделение в отдельный сервис оправдано, когда граница доменная уже ясна, часть функциональности нагружена и масштабируется иначе, чем остальной монолит, или над ней работает отдельная команда с собственным циклом релизов. Если проблема — просто в беспорядочных внутренних связях между Django apps, выделение сервиса добавит сетевые вызовы, согласованность данных между сервисами и операционную сложность, не решив исходную проблему связанности.
Подводные камни
- Риск. Разбивают монолит на микросервисы по формальному признаку (один Django app = один сервис) без анализа реальных доменных границ и паттернов нагрузки, получая распределённый монолит с теми же проблемами связанности, но уже через сеть; решают проблему связанности только организационно (переименование папок), не меняя фактические импорты и зависимости между apps.