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

Одно приложение, но не одна общая кухня
Представим интернет-магазин. Каталог, заказы, оплата и личный кабинет остаются внутри одного приложения. Оно собирается и обычно разворачивается целиком. В этом смысле перед нами по-прежнему монолит.
Разница в том, что у каждой области появляются собственные правила. Каталог не должен напрямую менять таблицы оплаты, а личный кабинет — вызывать внутренние функции заказов просто потому, что до них легко добраться. Общение идёт через оговорённые интерфейсы.
Это и есть модульный монолит: общая оболочка при достаточно самостоятельных частях. На иллюстрации отделы находятся в одном здании, но не ходят через стены в соседние помещения. Архитектуре тоже полезны двери.
Почему нарисованных границ недостаточно
Часто модули существуют только в диаграмме и структуре папок. Разработчик может импортировать любой класс, читать любые данные и обходить договорённости. Тогда при первой срочной задаче появляется исключение. Потом второе. Через некоторое время схема остаётся красивой, а реальная система — прежней.
Границы нужны не для презентации. Их закрепляют ограничением зависимостей между модулями, публичными интерфейсами, правилами владения данными и проверками в сборке или тестах. Физически база данных может оставаться одной, но чужие таблицы не должны становиться общедоступным интерфейсом.
Появляется ещё один вопрос: кто отвечает за модуль? Если у него нет владельца и правил изменения контрактов, даже хорошее разбиение кода не избавит команды от бесконечных согласований.
Что меняется для бизнеса
Выгода не в самом слове «модульный». Команда может разобраться с одной функцией, меньше затрагивая остальные. Новым людям проще понимать устройство продукта. Изменения становятся предсказуемее, если границы действительно соблюдаются.
При этом компания не обязана сразу поддерживать независимые развёртывания, сетевые контракты, отдельные механизмы обнаружения сбоев и согласования данных между сервисами. Значит, есть шанс направить больше работы на продукт, а не на обслуживание распределённой архитектуры.
Но независимые модули не означают независимые релизы. Если приложение поставляется целиком, командам всё ещё нужно договариваться о выпуске, а плохая автоматизация сборки или тестирования продолжит тормозить всех. Модульность не заменяет нормальный процесс поставки.
Где проходит предел
Допустим, расчёт рекомендаций внезапно начал потреблять большую часть ресурсов. Если он работает в общем процессе, проблема может сказаться и на оформлении заказа. Вынести расчёт отдельно — возможно, разумная идея. Но для этого нужен не просто отдельный каталог файлов.
Внутренний вызов функции и сетевой запрос — не одно и то же. После выделения сервиса понадобятся таймауты, повторные запросы, работа с частичными отказами, новые правила владения данными. Удобный интерфейс внутри монолита не всегда подходит для общения по сети без изменений.
Поэтому фраза «сделаем модульно, потом легко распилим» опасна. Хорошие границы облегчают возможный переход, но не делают его бесплатным.
Что проверять перед выбором
Я бы начал с неприятного: что именно сейчас мешает командам работать? Если каждая задача затрагивает несколько областей кода, стоит сначала разобраться с зависимостями. Если всё упирается в долгие согласования релизов, причина может оказаться в процессе. Если отдельная функция требует иного масштабирования и режима отказа — аргументы в пользу сервиса уже серьёзнее.
Для управленческого решения важны не количество модулей и не модная схема, а измеримые последствия: сколько изменений блокируют соседние команды, сколько времени занимает проверка и выпуск, что ломается при локальной ошибке, кто отвечает за границы и данные.
Иногда оптимальное решение — оставить монолит, но сделать его модульным. Иногда — выделить лишь одну действительно самостоятельную часть. Всё остальное можно не трогать.
Делить систему стоит тогда, когда цена общей жизни стала выше цены независимости. До этого полезнее научиться жить вместе, не заходя друг к другу через стену.
Смежные разборы: почему монолит может быть выгодным и когда микросервисы окупаются.