Привет, коллеги. На связи ваш покорный слуга — фулстек, 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).
В таком подходе:
- Поддерживать систему целиком проще, чем лоскутное одеяло из сервисов.
- Вы можете «выпилить» модуль в отдельный микросервис только тогда, когда бизнес действительно готов за это платить (когда модулю нужны независимые нагрузки, или когда команда выросла до 15 человек). До этого момента — это просто папка в коде.
- При разработке критически важно использовать подходы Чистой архитектуры. Именно из-за отсутствия понимания границ (Domain, Application, Infrastructure) создаются проблемы, а не из-за того, что у вас один процесс вместо десяти.
Фактор человека: Владелец продукта vs Разработчик
Отдельная боль, которую не лечит ни одна архитектура — это разное видение мира.
- У Владельца продукта (PO) свой взгляд: «Хочу фичу, чтобы кнопка была красной и приносила миллион».
- У Разработчика свой взгляд: «Нужна абстракция, паттерн Стратегия и рефакторинг ядра».
Именно постоянные компромиссы, неумение слушать и неспособность донести информацию друг до друга чаще всего убивают продукт. Микросервисы тут бессильны. Если бизнес и IT не говорят на одном языке, вы получите либо распределённый монолит, либо распределённое легаси.
Как мигрировать легаси без «сжигания ведьм»
На моей практике работы с легаси веб-системами отлично работает подход, который в узких кругах называют «Patstrangler» (паттерн фикуса-душителя «Strangler Fig Pattern»), но проще доносить смысл Владельцам, называя это: эволюционный вынос.
Мы не переписываем легаси с нуля (это путь к провалу). Мы берем критические узлы и выносим их в отдельный проект модульного монолита.
В старом легаси остаётся привычная форма, интерфейс и роутинг. А вся тяжелая бизнес-логика и новые фичи работают на стороне новой системы, которая выступает этакой «надстройкой» или тем самым «микросервисом» к разным частям легаси.
Плюс этого подхода в том, что миграция становится скучной формальностью. Переход на новые рельсы осуществляется без хватания за голову, без остановок бизнеса и без поиска виноватых.
Резюме
Микросервисы — это не панацея. Это дорогой и сложный инструмент для решения конкретных проблем масштабирования и автономии больших команд.
Прежде чем пилить монолит на части, задайте себе вопрос: у нас проблема в том, что код не помещается в голову, или в том, что мы просто не умеем писать чистый, структурированный код в принципе?
Всем чистого кода и адекватных Архитекторов! 🚀