Микросервисы — не панацея. Почему модульный монолит выигрывает у распределённого хаоса

«Сложно поддерживать не монолит или микросервис, а плохие инженерные решения внутри них. Микросервисы не убивают легаси, они просто дают ему отдельную квартиру с евроремонтом в Docker».

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

Разбираем инверсию чек-листа, ловушки процессов, преимущества модульного монолита и паттерн «Strangler Fig» для эволюционной, а не революционной миграции легаси.

Монолит против запутанных микросервисов

Привет, коллеги. На связи ваш покорный слуга — фулстек, CTO и человек, который за свои 20+ лет в IT видел столько архитектурных «серебряных пуль», что мог бы открыть из них тир.

Недавно мне попался отличный текст Александра Никитина про монолиты и микросервисы. Александр абсолютно прав в одном: границы важнее технологий. Монолит трещит по швам не от количества строк кода, а от когнитивной перегрузки команды. Его чек-лист из 5 вопросов — отличная диагностика.

Но давайте сыграем в игру. Давайте представим, что мы уже «распилили» систему на микросервисы. Над каждым микросервисом сидит отдельная команда из 4 разработчиков. Всего имеем три микросервиса.

И давайте прогоним те же самые 5 вопросов Александра, но уже через мясорубку микросервисной архитектуры. Спойлер: окажется, что «лекарство» иногда страшнее «болезни».

Инверсия чек-листа: как микросервисы создают проблемы

1. Можем ли мы за 5 минут нарисовать полную схему зависимостей текущей системы без документации?
В монолите: Ну, допустим.
В микросервисах: Ха! Хорошая шутка. В распределённой системе собрать полную схему зависимостей за 5 минут нереально. Каждая команда ведёт документацию как хочет: кто-то в Swagger, кто-то в Confluence, кто-то в Notion, а кто-то хранит её в голове у Васяна. Охватить всю систему СТО обязан в любом случае, и в микросервисах это превращается в квест «Найди 10 отличий» между тем, что написано в API-контракте, и тем, что реально отдаёт сервис в продакшене.

2. Сколько человек должны одобрить PR, чтобы изменить логику оплаты? Если больше двух — границы размыты.
В монолите: Логично.
В микросервисах: Одобрение PR зависит от процессов внутри команды, а не от архитектуры! Вот вам пример из жизни. В Команде А (сервис биллинга) строгий TDD, и PR ревьюят два человека. В Команде Б (интеграция с банками) сеньор смотрит код один, потому что «я же говорил». А в Команде В (история транзакций) вообще собирают дейли-митинг на 15 человек, чтобы обсудить изменение одной колонки в БД. Архитектура тут ни при чём, это культура разработки.

3. Как часто релизы откладываются из-за конфликтов в смежных фичах?
В монолите: Часто, всё в одной куче.
В микросервисах: О, тут мы собираем новые, экзотические грабли! Представьте: Команда 1 делает Шлюз платежей и хочет выпустить мажорное обновление на v2.0. А Команды 2 и 3 делают микросервисы конкретных платёжных решений и они ещё на v1.0. Что происходит? Шлюз теперь обязан поддерживать и v1, и v2. Релиз Шлюза тормозится, потому что «ребята из крипто-оплаты ещё не допилили». Хвост начинает вилять собакой. Конфликты не исчезли, они просто сместились с уровня кода на уровень сетевых контрактов и версионирования.

4. Есть ли модули, которые никто не хочет трогать ("там мины", "там живут драконы")?
В монолите: Да, это «тёмные леса» легаси.
В микросервисах: Всё так же! Только теперь у этого «дракона» есть собственный репозиторий, свой CI/CD пайплайн и свой выделенный сервер. «Не лезь в сервис legacy-billing-core, он написан на COBOL, документацию потеряли в 2018 году, а разработчик ушёл в стартап». Микросервисы не убивают легаси, они просто дают ему отдельную квартиру с евроремонтом в Docker.

5. Хотят ли две части продукта развиваться с разной скоростью?
В монолите: Это боль.
В микросервисах: В микросервисах они обречены развиваться с разной скоростью. И это порождает новые проблемы. Админка развивается стабильно, а клиентский API — каждую неделю. Но какой смысл в развитии админки, если она не может отобразить новые фичи из API, потому что контракт поменялся три раза за день? Рассинхрон скоростей приводит к тому, что бизнес-ценность размывается.

Настоящий враг: не архитектура, а процесс

Ответили на вопросы? Если честно, то микросервисы часто имеют больше проблем, чем решений, если применять их как религию.

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

Посмотрите на магазины, сделанные на WordPress. Меня не покидает ощущение, что смотрю на Франкенштейна. Казалось бы, зачем к блоговому движку на костылях прикручивать e-commerce, а потом на конференциях ругать монолитную архитектуру самого WP? Проблема не в монолите. Проблема в том, что инструмент использовали не по назначению.

С другой стороны, в микросервисах часто уходят в другую крайность. Обмазываются «докерами», настраивают Kubernetes, пишут оркестраторы, и в итоге тратят 70% бюджета на поддержку инфраструктуры и DevOps-инженеров, и только 30% — на разработку фич для бизнеса. Суть проекта теряется за шумом сетевых вызовов.

Что же делать? Модульный монолит и Чистая архитектура

Александр абсолютно прав: нужны границы. Но границы не требуют сетевых вызовов.

Границы можно и нужно выделять внутри монолита. Из этого рождается Модульный монолит — архитектура, при которой проект состоит из четко ограниченных модулей. Каждый модуль инкапсулирует свою бизнес-логику (привет, DDD), общается с другими только через публичные интерфейсы и покрыт тестами (привет, TDD).

В таком подходе:

  1. Поддерживать систему целиком проще, чем лоскутное одеяло из сервисов.
  2. Вы можете «выпилить» модуль в отдельный микросервис только тогда, когда бизнес действительно готов за это платить (когда модулю нужны независимые нагрузки, или когда команда выросла до 15 человек). До этого момента — это просто папка в коде.
  3. При разработке критически важно использовать подходы Чистой архитектуры. Именно из-за отсутствия понимания границ (Domain, Application, Infrastructure) создаются проблемы, а не из-за того, что у вас один процесс вместо десяти.

Фактор человека: Владелец продукта vs Разработчик

Отдельная боль, которую не лечит ни одна архитектура — это разное видение мира.

  • У Владельца продукта (PO) свой взгляд: «Хочу фичу, чтобы кнопка была красной и приносила миллион».
  • У Разработчика свой взгляд: «Нужна абстракция, паттерн Стратегия и рефакторинг ядра».

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

Как мигрировать легаси без «сжигания ведьм»

На моей практике работы с легаси веб-системами отлично работает подход, который в узких кругах называют «Patstrangler» (паттерн фикуса-душителя «Strangler Fig Pattern»), но проще доносить смысл Владельцам, называя это: эволюционный вынос.

Мы не переписываем легаси с нуля (это путь к провалу). Мы берем критические узлы и выносим их в отдельный проект модульного монолита.

В старом легаси остаётся привычная форма, интерфейс и роутинг. А вся тяжелая бизнес-логика и новые фичи работают на стороне новой системы, которая выступает этакой «надстройкой» или тем самым «микросервисом» к разным частям легаси.

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

Резюме

Микросервисы — это не панацея. Это дорогой и сложный инструмент для решения конкретных проблем масштабирования и автономии больших команд.

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

💡 Главный вывод: Если второе — микросервисы только умножат вашу боль на количество сетевых задержек. Начинайте с границ в голове, с DDD, с тестов и с модульного монолита. А «распиливать» будете только тогда, когда бизнес действительно попросит об этом, и сможет за это заплатить.

Всем чистого кода и адекватных Архитекторов! 🚀

Обсуждение

💬 Есть вопросы? Пишите в Telegram-канал или на ping@ambrion.dev