На конференциях эта тема (монолит vs микросервисы) обсуждается с завидной регулярностью, но обычно в техническом ключе. Кто-то любит консистентность монолита, кто-то гибкость микросервисов, какие-то инструменты удобнее, какие-то нет.
Очень мало обсуждается вопрос команд и их взаимодействия, а ведь это самое главное при выборе. Я написал небольшую заметку в одном телеграм-канале, и в результате последующих обсуждений незаметно выросла целая статья на Хабр.
Поехали.
Итак, главное — это организационная структура компании и процессы взаимодействия команд. Да-да, как всегда, не технологии, а люди. Сейчас я работаю в Каруне, до этого работал в компаниях поменьше, видел, как набивались шишки, поэтому могу сравнить.
Одна команда
Когда команда одна, не очень большая (two pizza team), то никто никому не мешает. Код ревью, рефакторинг, деплой проходят быстро и весело. Бизнес сфокусирован на цели и работает как единое целое. Целью, кстати, зачастую является проверка гипотезы, нужен ли вообще этот проект кому-то или нет.
Для одной команды нет большого смысла дробить программу на части: пусть это будет один бинарник (или набор php-файлов), который билдится из одного репозитория. С одной единственной базой данных. Разделение кода на несколько полностью независимых логических единиц со своими хранилищами будет тормозить процесс, не давая никаких преимуществ.
В монолите очень просто писать код, дебажить, тестировать и т.д. — всё перед глазами.
Единственное, что лучше сделать — это внутри монолита поддерживать хотя бы какую-то модульность, чтобы в будущем было легче это отделять. И в данных тоже: хотя база одна, никто не мешает сделать несколько схем (термин PostgreSQL).
Две-три команды
Команда разработки рано или поздно вырастает и вынуждена разделиться на две, иначе ей будет слишком сложно управлять. В правильной организации команды делятся не по технологиям (а-ля фронтенд и бекенд), а по бизнес-направлениям.
Чтобы две разные по смыслу команды могли работать быстро и эффективно, им необходимо разделить все процессы. Они не должны согласовывать действия друг друга по каждому чиху: ждать чьего-то рефакторинга, смены фреймворка, апрува другого лида, ожидания билда, тестов, деплоя, и бог знает чего. Надо откатить что-то — откатываешь и не боишься конфликтов в коде. Надо накатить — накатываешь в любой момент.
![](https://habrastorage.org/webt/gd/cp/t8/gdcpt8ivju_29jwmh7oac_gmbye.png)
Я абсолютно уверен, что это возможно только тогда, когда код этих команд полностью независим, базы данных независимы, а билд и деплой идут в отдельные приложения.
Это уже можно назвать микросервисами, но с большой-пребольшой натяжкой. Скорее, это сервисы. Пока ещё нет ни смысла, ни возможности дробить программы на совсем уж мелкие части, потому что это несёт дополнительные расходы. Даже если очень хочется.
Пока что управлять кодом, тестировать и деплоить очень легко. Не нужен даже никакой kubernetes, нужен лишь достаточно бородатый админ.
Дофига команд
Когда команд много, они, разумеется, также должны быть независимыми друг от друга, чтобы time-to-market был минимальным. Это ключевой момент, и он остается неизменным с самого рождения проекта и до самого его конца. При этом в полный рост встают такие проблемы, как:
- А как нам сделать тестовое окружение, чтобы посмотреть на этот зоопарк полностью или частично (сэкономить ресурсы)
- А как нам создавать и потом управлять таким количеством баз данных
- А как нам поддерживать актуальную документацию всех API и взаимодействий через Kafka
- А не надо ли нам сделать отдел солюшн-архитекторов, которые будут способны разобраться, где чьё, и куда
- А как насчет единой системы логирования, метрик и трейсинга
- А не надо ли сделать генератор бойлерплейта для нового сервиса
- А если всё упадёт, как найти того, кто это всё будет чинить
- Ой, а фронтенд тоже надо делить на независимые части, иначе команды ждут друг друга
Обычно появляется ещё одна, особая, платформенная команда, которая пытается упростить всё, что можно.
И вот когда сервисов много, и всё поставлено на промышленные рельсы, тогда можно дробить код на логические части как угодно: хоть по микросервису на каждый бизнес чих. И это начнёт приносить свои плоды:
- Никакой DDD и прочие заумные практики разработчикам уже не нужны (микросервисы и так обеспечивают bounded contexts), на код ревью тоже не будет много споров из-за неправильных абстракций, ведь там скорее всего будет лишь несколько эндпоинтов и пара табличек. Качество кода, если честно, становится вообще не особо важным, лишь бы работало и было протестировано. Навороченные многофункциональные фреймворки не нужны. Поэтому, кстати, для микросервисов очень популярен язык Go — работает быстро, памяти ест мало. Да, крутых абстракций нет — но в микросервисах не очень-то и надо.
- Баз данных много, но они очень просты. Если база падает, то сразу понятно, почему.
- Редко, когда больше 1-2 человек работает над одним и тем же кодом, поэтому merge-конфликты — большая редкость.
UPDATE про DDD: Я имею в виду, что в случае микросервисов разделение предметной области на подобласти больше не делается в коде, а продумывается на уровень выше. Больше не нужно поддерживать дисциплину в коде одного приложения, чтобы разделять там логику на части. Если взаимодействие между микросервисами продумано, то сам код каждого из них тривиален
Что будет, если поступать наоборот
![](https://habrastorage.org/webt/cl/gf/ss/clgfssu7rtyqhhdxgm6arrblhze.png)
Если начать с микросервисов в компании из трех человек, то сразу нужно пилить много инфраструктурных и организационных моментов, перечисленных выше. Т.е. дело не в том, что лучше выбрать, кубер или другое решение, дело тупо в цене: много, много, очень много работы без малейшего бизнес-результата. Вся команда только этим и будет заниматься.
Если не перейти на микросервисы в огромной компании, то у вас будут миллионы строк кода в одном приложении, базы данных адового размера, над которыми ночами чахнут десятки дба, а главное — выкатить и откатить код будет прям событием, как спуск Титаника на воду. 100% будет навороченная система управления ветками и фича-флагами, в которой фиг разберешься. Т.е. код-то писать просто, но на проде ему появиться очень сложно.
Взять хотя бы VK. Я честно не понимаю, как они работают, у них вся логика в одном монолите на KPHP (около 8 млн строк, насколько я слышал), который компилируется в С++, который тоже, блин, надо компилировать! Т.е процесс долгий и непростой. А что если надо откатить баг, а за это время 100 человек уже написали овердофига нового кода? Что откатывать, что нет? А что если надо выкатить хот фикс, чтобы устранить дыру в безопасности? Сколько это займёт, полдня? Ребята из VK, поделитесь плиз, как вы это делаете, какой у вас time-to-market?? Ну очень любопытно.
Исключения
Бывают, конечно, исключения, как и везде. Иногда сразу ясно, что какая-то часть системы должна быть отдельной, и иначе никак. Например, если делаете рекламную сеть, то панель управления рекламными кампаниями и собственно система показа рекламного баннера, скорее всего, сразу должны быть двумя отдельными сервисами. Просто потому, что рекламный баннер точно будет хайлоад системой, иначе в нём никакого бизнес-смысла вообще нет.
Еще слышал про кейсы с ERP системами, где констистентность настолько важна, что разделять на микросервисы получится просто намного дороже, если вообще возможно.
Вывод
Бизнесу практически всегда нужен хороший time-to-market — отсюда всё остальное и вытекает. Микросервисы, необходимые технологии, независимость команд, и так далее.