Misha_Backend
2026-08-03 14:24
Все мы прошли через фазу, когда хотелось выстроить систему как по учебнику: чистая гексагональная архитектура, event-driven, CQRS, саги, outbox — и чтобы всё это работало как часы. Я тоже так хотел. Пока не попал на проект, где требования меняются быстрее, чем я успеваю переименовать миграции, а «бизнес-логика» в голове заказчика — это просто «сделай, чтобы работало, а детали потом».
Смотрите, в чём проблема. Мы, бэкендеры, любим строить красивые абстракции. Разбиваем монолит на микросервисы, вводим доменные события, оборачиваем всё в репозитории. Но через полгода выясняется, что 80% сервисов — это просто CRUD с одним эндпоинтом, а вся «сложность» — в инфраструктуре: Kafka, Redis, оркестратор. И вот ты сидишь и думаешь: зачем я здесь городил сагу, если можно было просто вызвать REST из другого сервиса и не париться с компенсациями?
Я не говорю, что архитектура не нужна. Я говорю, что нужно проектировать под хаос — то есть под реальные условия эксплуатации. Возьмём пример: у вас есть сервис заказов и сервис оплаты. По учебнику — асинхронная коммуникация через брокер, outbox-паттерн, обработка дублей. По факту — вам нужно, чтобы заказ создался и оплата прошла в течение секунды, иначе юзер уйдёт. Если вы воткнёте между ними Kafka, вы добавите задержку и кучу точек отказа. Проще сделать синхронный вызов с retry и идемпотентностью. Да, это «не идеально», но это работает и легко дебажится.
Второй момент — это переиспользование. Я как-то видел проект, где для каждой сущности создавали отдельный микросервис. В итоге было 40 сервисов, из которых 35 — это одинаковые CRUD с разными полями. Поддерживать это — ад: каждый сервис со своим деплоем, логами, метриками. Я бы сделал один generic-сервис с конфигурацией, но нет — «архитектурные принципы» не позволяли. Так вот, принципы должны быть гибкими. Если у вас двадцать раз повторяется одно и то же — это не «микросервисы», это плохой дизайн.
Теперь про базы данных. Вечная тема: PostgreSQL всем хорош, но вот NoSQL модно. Я видел, как люди переносили на MongoDB то, что отлично жило в реляционке, а потом мучились с агрегациями и транзакциями. Мой подход: если данные связаны и нужны отчёты — это SQL. Если это лог событий или кэш — Redis или что-то подобное. Не надо лепить графовые базы для дружбы юзеров, если хватит таблицы friends с индексами. Простота — это тоже архитектура.
Ещё один пункт — тестирование. Я перестал писать юнит-тесты на каждый чих. Серьёзно. Если у меня есть интеграционные тесты, которые гоняют реальный сценарий через БД и брокер, они ловят больше багов, чем сотни моков. Моки — это иллюзия безопасности: они тестируют ваши ожидания, а не реальность. Поэтому я теперь сначала пишу e2e-сценарий, а потом уже покрываю критичные куски юнитами. Это экономит кучу времени и нервов.
И последнее — про мониторинг. Любая, даже самая уродливая архитектура, становится терпимой, если у тебя есть хорошие логи и трейсинг. Я в каждом сервисе прокидываю request ID, собираю метрики в Prometheus и строю дашборды. Когда что-то падает, я не гадаю — я вижу, где именно. Это спасло меня от десятков ночных инцидентов. Без этого ваша идеальная архитектура — просто груда кода, которая рано или поздно взорвётся.
Так что мой совет: не бойтесь выглядеть «недостаточно архитектурно». Бойтесь того, что система не переживёт контакт с реальностью. Проектируйте под хаос, упрощайте, где можно, и всегда помните: код пишется для людей, а не для абстрактных паттернов. Если кто-то скажет, что ваш сервис «не по канону» — предложите ему поддержать это в проде.
Кстати, кто как решает проблему «синхронный вызов vs брокер» на практике? Может, у кого-то есть конкретные критерии, кроме «так принято»? Был бы благодарен за аргументы.
👍 2