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

Микромодуль выделяют не ради меньшего числа строк в файле, а ради управляемых изменений: одна команда или разработчик меняет часть системы, не затрагивая соседние сценарии. Проблема в том, что термин не стандартизирован: без явной границы микромодули превращаются либо в папки для вида, либо в распределённый монолит с десятками зависимостей.
Что считать микромодулем
Микромодуль — небольшая функциональная единица внутри приложения с собственной ответственностью, ограниченным интерфейсом и контролируемыми зависимостями. Он может жить в монолите, библиотеке или фронтенд-приложении. В отличие от микросервиса, микромодуль не обязан иметь отдельный процесс, базу данных, сетевой API или независимый релиз.
Размер здесь вторичен. Модуль из нескольких десятков файлов может быть хорошо изолирован, а один файл на 300 строк — нет, если он знает о базе данных, HTTP-формате, бизнес-правилах и деталях интерфейса одновременно.
Сноска. Под «границей модуля» понимается место, через которое он взаимодействует с остальной системой: публичные функции, классы, события, команды или другой явно описанный контракт.
Хороший микромодуль уменьшает область изменений. Если после его выделения приходится править пять соседних частей, границу выбрали не там.
Зачем его выделять
Выгода появляется там, где код меняется неравномерно. Например, правила расчёта доставки меняются каждую неделю, а отображение заказа — раз в несколько месяцев. Если они смешаны в одном компоненте, любое изменение доставки требует проверять весь экран и его побочные эффекты.
Микромодуль может дать четыре практических преимущества:
- Локальность изменений. Новое правило затрагивает один пакет или каталог, а не весь проект.
- Понятный контракт. Соседний код видит только необходимые операции и данные.
- Отдельное тестирование. Бизнес-правила можно проверять без запуска HTTP-сервера, браузера или всей базы.
- Контроль владения. Команде проще договориться, кто отвечает за решение и его обратную совместимость.
Цена тоже реальна. Появляются преобразования данных, документация, тесты контракта и правила импорта. Маленькую функцию, которую вызывают в одном месте, иногда дешевле оставить рядом с вызывающим кодом.
Как выбрать границу
Начинайте с причины изменения
Соберите несколько последних задач по проекту и отметьте, какие файлы менялись вместе. Если набор файлов постоянно изменяется одной группой требований, это кандидат на модуль. Если два участка всегда редактируются одновременно, их раннее разделение создаст лишнюю прослойку.
Полезный вопрос звучит так: «Какую часть системы можно изменить, не заставляя читателя изучать остальные?» Ответ должен описывать пользовательское или бизнес-поведение, а не технический слой вроде «всё, что связано с моделями».
Проверьте зависимости
Микромодуль не обязан быть полностью независимым, но направление связей должно быть понятным. Например, модуль заказов может использовать расчёт доставки, однако модулю доставки не стоит импортировать экран заказа и знать о структуре его состояния.
Особенно опасны циклические зависимости. Они возникают, когда модуль A вызывает B, B вызывает C, а C снова обращается к A. Сначала это выглядит как удобный обмен готовыми объектами, но затем любое изменение требует понимать весь цикл.
Опишите контракт до переноса файлов
Контракт должен отвечать на три вопроса:
- какую операцию вызывает внешний код;
- какие данные входят и выходят;
- какие ошибки или состояния считаются частью поведения.
Внутренние классы, таблицы и вспомогательные функции не должны становиться случайным публичным API. Чем больше наружу опубликовано деталей, тем дороже будет последующее изменение.
Три подхода и их цена
| Подход | Когда подходит | Что выигрываете | Чем платите |
|---|---|---|---|
| Оставить код рядом с вызывающим местом | Логика короткая и используется в одном сценарии | Минимум абстракций и файлов | Повторное использование и рост файла могут усложнить дальнейшие изменения |
| Выделить микромодуль внутри приложения | Есть отдельное правило, несколько сценариев или самостоятельный жизненный цикл | Локальные тесты, понятный контракт и контроль зависимостей | Нужны интерфейс, преобразование данных и правила владения |
| Вынести в отдельный сервис | Нужны независимое масштабирование, релиз или изоляция отказов | Самостоятельный процесс и сетевые границы | Сеть, мониторинг, доставка, согласованность данных и операционные расходы |
Если задача решается внутренней границей, сетевой сервис будет избыточным. Распределение по процессам не делает архитектуру автоматически модульной: оно лишь добавляет ещё один тип связи — сетевой.
Типичные ошибки
Ошибка 1. Делить по техническим слоям
Каталоги controllers, services и repositories могут быть удобны, но сами по себе не создают микромодули. Для изменения одной функции разработчику всё равно приходится искать код в трёх-четырёх слоях и проверять их скрытые связи.
Практичнее группировать рядом код, который меняется по одной причине: например, оформление заказа, расчёт скидки или импорт каталога. Внутри такой области слои допустимы, если они не разрывают понимание сценария.
Ошибка 2. Делить по размеру файла
Перенос каждой функции в отдельный файл создаёт визуальный порядок, но не архитектурную границу. Если новый файл импортирует внутренности пяти соседей, это не изоляция, а разнос связанного кода по проекту.
Перед выделением ответьте, какую зависимость вы хотите запретить. Если запрет сформулировать нельзя, дробление, скорее всего, преждевременно.
Ошибка 3. Публиковать внутренние детали
Модуль может вернуть наружу объект базы данных, внутреннюю модель или структуру, созданную конкретным фреймворком. Тогда внешний код начинает зависеть от деталей реализации, и заменить их уже нельзя без массовых изменений.
Граница должна передавать данные, нужные вызывающему сценарию, а не всё, что удобно получить внутри. Иногда это означает отдельный объект результата или небольшой набор значений.
Ошибка 4. Делать общий модуль для «всего полезного»
Папка common, utils или shared быстро становится складом функций без единого владельца. Через несколько месяцев в ней оказываются форматирование дат, права доступа, скидки и отправка писем.
Общая библиотека допустима для действительно универсальных примитивов. Но правило должно быть жёстким: функция попадает туда не потому, что её можно переиспользовать, а потому, что у неё стабильная ответственность и несколько реальных потребителей.
Ошибка 5. Проводить рефакторинг без проверки поведения
После переноса кода меняются не только импорты. Могут измениться порядок вызовов, обработка ошибок, транзакции, логирование и момент загрузки данных. Поэтому выделение нужно сопровождать тестами на внешний контракт, а не только тестами отдельных новых файлов.
Как понять, что граница неудачна
Проблему видно по повторяющимся сигналам:
- для простой задачи приходится менять публичный интерфейс сразу в нескольких модулях;
- модуль импортирует внутренние файлы соседей, минуя их публичный вход;
- одни и те же данные преобразуются между модулями несколько раз;
- тест модуля требует поднять весь application stack;
- никто не может назвать владельца правил и решить, кто меняет контракт.
Один такой сигнал не доказывает ошибку. Но если они повторяются в каждом изменении, граница стала источником связности, а не способом её уменьшить.
Как выделять без большого переписывания
- Выберите один сценарий. Не переносите сразу весь домен. Возьмите операцию с понятным входом и результатом.
- Зафиксируйте текущее поведение. Добавьте тесты на успешный путь, ошибки и побочные эффекты, которые нельзя потерять.
- Спрячьте внутренности. Оставьте наружу минимальный набор вызовов, а прямой доступ к внутренним структурам постепенно уберите.
- Перенесите реализацию. Сначала сохраните поведение, а оптимизацию и переименование сделайте отдельными изменениями.
- Проверьте зависимости. Найдите циклы, лишние импорты и обращения к базе или сети, которые неожиданно пересекли границу.
- Оцените следующий релиз. Посмотрите, уменьшился ли список файлов в типичной задаче. Если нет, пересмотрите границу, а не добавляйте новые уровни.
Такой порядок снижает риск: каждый шаг можно откатить, а результат проверяется по поведению и стоимости изменений, а не по числу созданных каталогов.
Когда микромодуль лучше не выделять
Не выделяйте отдельную единицу, если логика короткая, используется один раз и почти всегда меняется вместе с вызывающим кодом. Не стоит также отделять участок только потому, что «так принято» в другой команде или фреймворке.
Отдельный сервис тем более не нужен, если единственная цель — сделать код красивее. Для этого сначала достаточно внутреннего модуля, статического анализа зависимостей, тестов и понятного соглашения об импортах.
Что делать дальше
Возьмите одну недавнюю задачу и выпишите файлы, которые пришлось изменить. Отдельно отметьте данные, пересекающие границу, и места, где модуль обращается к внутренностям соседа. После выделения сравните не количество файлов, а три показателя: число изменённых компонентов, количество циклических зависимостей и время прохождения тестов.
Если граница выдерживает несколько изменений, закрепите её в документации проекта и автоматической проверке импортов. Инвалидация кеша, владение схемой базы и переход к микросервисам — отдельные архитектурные темы; не смешивайте их с первым выделением микромодуля.
Карточки для маркетплейсов: Таблица товаров и папка фотографий на входе — комплект слайдов и описаний на выходе, по требованиям Wildberries и Ozon.
Спросить за 5 ₽Источники: Modular Monolith, Microservices
Частые вопросы
Чем микромодуль отличается от микросервиса?
Сколько файлов должно быть в микромодуле?
Нужно ли сразу выносить микромодуль в отдельный пакет?
Что делать, если два микромодуля постоянно импортируют друг друга?
Можно ли выделить микромодуль в уже работающем монолите?
Что делать, если после выделения стало больше кода?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.