Меня зовут Михаил Кузнецов, я product owner в команде, которая развивает внутреннюю платформу разработки Mindbox. В этой статье я расскажу, как мы отказались от легаси-фреймворка, который пронизывал все микросервисы. И убедились — такая трансформация осуществима даже в компании на 100+ разработчиков и 1000+ корпоративных клиентов.
Что за фреймворк и откуда он появился
Mindbox — это облачная платформа автоматизации маркетинга. Ей пользуются маркетологи, чтобы отправлять рассылки, настраивать ботов, виджеты и баннеры, внедрять программы лояльности. В 2008 году у нас было немного клиентов, и мы писали вручную код для каждой новой фичи: от рекламной акции в рассылке до скидок на сайте.
Спустя год клиентов стало в четыре раза больше, и мы стали думать, как автоматизировать разработку фич. Чтобы уменьшить ручной труд и автоматизировать типовые действия, написали базу, вокруг которой можно строить кастомизацию. Эту базу мы назвали фреймворком.
Фреймворк должен был забирать на себя все вопросы, не относящиеся к написанию бизнес-логики: работу с базой данных, валидацию, сериализацию, обработку и категоризацию ошибок и еще 20 аспектов. Достаточно быстро в него начали добавлять всё подряд, включая средства для построения админок — учётки/пермиссии, элементы ui и прочее, что уж точно не является универсально-необходимым в каждом сервисе.
Долгое время фреймворк развивался и облегчал разработку. Но со временем стал слишком большим и начал мешать.
Когда фреймворк стал приносить проблемы
Изначально фреймворк работал на .NET 4.8. В 2021 году это уже стало жутким легаси — мы перешли на .NET Core и портировали на него фреймворк. В это время стали остро чувствовать три проблемы:
1. Фреймворк стал узким горлышком. Разработчикам часто приходилось вносить изменения во фреймворк, и каждый раз это давалось с болью. Версия постоянно обновлялась, нужно было подтягивать изменения. Если одновременно работали несколько человек, начиналась война правок. А потом кто-то вносил несовместимые правки — и всё приходилось начинать заново. В итоге разработчики тратили до 4 часов в день только на то, чтобы залить изменения во фреймворк.
2. Микросервисы с трудом работали с монолитным фреймворком. В какой-то момент фреймворк превратился в библиотеку на несколько десятков тысяч строк. Когда его использовали в сервисе-монолите, все было нормально. Но когда мы перешли на микросервисную архитектуру, это стало проблемой.
Доходило до абсурда: сам микросервис умещается в 1000 строк, но за ним тянется фреймворк на 50 000 строк. Например, нужно сделать тривиальный микросервис: без БД, Redis и работы с шиной. А фреймворк так не может — он должен стартовать из сконфигурированной БД и просит от этого бедного микросервиса Redis. А если Redis нет, то падает на старте.
Вместо скорости и feedback loop мы получали от микросервисов почти то же, что от монолита.
3. Нанимать людей на работу было сложно. Разработчики хотят работать с новыми технологиями, перенимать востребованный опыт. А наш фреймворк — вообще не об этом: новым людям приходилось обучаться у нас тому, что нигде не пригодится и не повысит их ценность. Из-за этого падала наша привлекательность как работодателя и осознанные специалисты отказывались к нам идти.
Как начали борьбу с фреймворком
Пока фреймворк мучал разработку Mindbox, я успел уволиться и поработать в другой компании. Я увидел мир без фреймворка и легаси и в 2021 году вернулся в Mindbox с настроем все поменять.
Я предложил декомпозировать фреймворк до отдельных небольших решений под каждую потребность: например, свой инструмент для работы с конфигами, для деплоя, кеширований, миграций в БД.
Идея была прекрасной, и все это признали. Но недостижимой: мы не могли остановить конвейер разработки, чтобы перенести всё с фреймворка. Не было понимания как безопасно «есть слона по частям», а целиком слон выглядел страшно. Тем более инвестиции в сырую идею — риск, который мы не могли себе позволить: вдруг для очередной задачи не нашлось бы подходящего решения.
Первый отказ меня не остановил, и я начал прорабатывать идею самостоятельно. Выписал список задач, с которыми помогает справляться фреймворк. Для большинства из них удалось найти решения, которыми умеет пользоваться любой разработчик с рынка: от опенсорс-сообщества, Microsoft или других поставщиков. Недостающие дописывал в отдельных библиотеках с документацией на API и нормальным скоупом.
Когда набралось достаточно инструментов, чтобы запустить базовый микросервис без фреймворка, сделал второй заход, чтобы «продать» идею команде. На этот раз мне выделили в помощь двоих джунов-разработчиков. Вместе мы разработали первые микросервисы без старого фреймворка — самые простые с точки зрения необходимой инфраструктуры и библиотек.
Когда доказали, что работать без фреймворка возможно, коллеги стали присматриваться к нашему решению. Постепенно команды отказывались от фреймворка и вместе мы создавали пул инструментов, заменяющих его. Например, когда в микросервисе требовалась валидация, находили известную библиотеку — FluentValidation. Если известное решение было неудобно, делали адаптер, к примеру MindboxValidation на базе FluentValidation — под капотом была технология, с которой все на рынке умели работать, а снаружи — привычный API.
Меньше чем за год мы стали делать все микросервисы без фреймворка. Новые функции проходили проверку в бою, доказывали свою эффективность, и поэтому люди были готовы их использовать. А если решения для какой-то задачи не хватало, то быстрее было потратить найти решение, чем тащить фреймворк.
Что получили, отказавшись от фреймворка: довольных сотрудников и 70+ новых микросервисов
Разработка стала производительнее. Без фреймворка стало проще запускать новые микросервисы. С 2010 по 2024 год мы написали 100+ микросервисов. Из них 70+ написаны с середины 2022 по 2024, когда мы отказались от фреймворка.
Микросервисы — быстрее. Параллельно с отказом от фреймворка мы переезжали в Kubernetes. Его особенность в том, что в нем постоянно поднимается много маленьких подов с микросервисами. Поды с микросервисами на фреймворке стартовали долго, скажем, десяток секунд или больше, а без фреймворка стали подниматься буквально за секунду. С тестами тоже стало проще — они без легаси-обвеса проходят быстрее.
Проще нанимать и онбордить сотрудников. Теперь мы не зовем людей работать с легаси и не отпугиваем этим толковых кандидатов. К тому же раньше новичков приходилось обучать работе с нашим фреймворком — теперь все решения актуальные, онбордить стало проще.
Довольные разработчики. Мы провели опрос среди разработчиков — узнали, как они оценивают эффективность своей работы. В командах, которые отказались от фреймворка, показатель удовлетворенности был 8,7, тогда как у тех, кто остался на нем, — 5.
Результаты разработчиков монолита
Результаты разработчиков микросервисов
Главное, что я сам вынес из этой истории — не обязательно быть генеральным директором, чтобы принимать решения, которые упрощают жизнь команде и приносят прибыль компании. Можно начать изменения с себя, получить небольшой результат и уже его использовать, чтобы получить обратную связь и поддержку коллег.
Комментарии (12)
CitizenOfDreams
04.10.2024 08:01+3фреймворк работал на .NET 4.8. В 2021 году это уже стало жутким легаси
Я напомню, что .NET 4.8 вышел в апреле 2018 года. А в 2021 году работающий на нем фреймворк уже стал "жутким легаси"? Какие-то однодневные фреймворки в этом вашем IT...
Einherjar
04.10.2024 08:01+7Я напомню, что .NET 4.8 вышел в апреле 2018 года
Какие-то однодневные фреймворки в этом вашем IT
4.8 легаси уже был фактически на момент выхода, потому что то что тогда называли .NET Core уже активно параллельно развивался и всем было понятно что будущее за ним
mayorovp
04.10.2024 08:01+4.NET 4.* - это legacy в принципе:
принципиальное отсутствие поддержки .NET Standard 2.1;
принципиальная несовместимость с некоторыми свежими фичами языка C#;
устаревшая система сборки в комплекте;
ужасные конфигурационные файлы, в которых смешиваются настройки платформы и настройки приложения;
устаревшая архитектура системных классов (особенно в System.Web).
Многие вещи ощущались как неизбежное зло в 2016м году, но начиная с выхода .NET Core 2.0 вся старая ветка .NET перешла в категорию "всё ещё приходится использовать, но уже хочется свалить". А это и есть legacy.
Соответственно, все версии 4.7.1, 4.7.2, 4.8 и 4.8.1 были legacy ещё в момент релиза.
pintor
04.10.2024 08:01Если известное решение было неудобно, делали адаптер, к примеру MindboxValidation на базе FluentValidation — под капотом была технология, с которой все на рынке умели работать, а снаружи — привычный API.
Интересно было-бы пример посмотреть. Особенно - что было "неудобным" и как выглядит "привычный API".
Mijka64 Автор
04.10.2024 08:01Тут дело не в том, что у либы API плохой.
Дело в том, что есть уже 500 или 5000 старых usages , править которые - долго и муторно, и проще сделать какой-то промежуточный слой.
При этом новое писать можно уже без него, конечно.
Driver86
04.10.2024 08:01+1я успел уволиться и поработать в другой компании
и в 2021 году вернулся
Как? Или просто в компании так и не смогли найти нового разработчика?
Mijka64 Автор
04.10.2024 08:01Я вопрос "как?" не понял. Так же, как и всегда - люди меняют работу. Что тут удивляет?
В компании в тот год наняли около 30 разработчиков, большую часть сеньоров - я лично. Могу поделиться опытом, если у вас это болит.
yoz
Странно, что это не было сделано при переходе с монолита на микросервисы.
Mijka64 Автор
Каждый следующий микросервис - небольшая задачка, в рамках которой вроде как нет запаса инвестировать в поиск 3-5-7 технологий с рынка и проверку их пригодности для своих задач, как-то так.