Меня зовут Михаил Кузнецов, я 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 по 2022 год мы написали 100+ микросервисов. Из них 70+ написаны с середины 2022 по 2024, когда мы отказались от фреймворка. 

Микросервисы — быстрее. Параллельно с отказом от фреймворка мы переезжали в Kubernetes. Его особенность в том, что в нем постоянно поднимается много маленьких подов с микросервисами. Поды с микросервисами на фреймворке стартовали долго, скажем, десяток секунд или больше, а без фреймворка стали подниматься буквально за секунду. С тестами тоже стало проще — они без легаси-обвеса проходят быстрее.

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

Довольные разработчики. Мы провели опрос среди разработчиков — узнали, как они оценивают эффективность своей работы. В командах, которые отказались от фреймворка, показатель удовлетворенности был 8,7, тогда как  у тех, кто остался на нем, — 5. 

Результаты разработчиков монолита

Результаты разработчиков микросервисов

Главное, что я сам вынес из этой истории — не обязательно быть генеральным директором, чтобы принимать решения, которые упрощают жизнь команде и приносят прибыль компании. Можно начать изменения с себя, получить небольшой результат и уже его использовать, чтобы получить обратную связь и поддержку коллег. 

Комментарии (4)


  1. yoz
    04.10.2024 08:01
    +2

    Странно, что это не было сделано при переходе с монолита на микросервисы.


  1. sidristij
    04.10.2024 08:01
    +3

    Если у вас фреймворк настолько жёсткий, что надо было подключать бд даже если она не нужна, тут проблема скорее в тех, кто его написал ))


  1. CitizenOfDreams
    04.10.2024 08:01

    фреймворк работал на .NET 4.8. В 2021 году это уже стало жутким легаси

    Я напомню, что .NET 4.8 вышел в апреле 2018 года. А в 2021 году работающий на нем фреймворк уже стал "жутким легаси"? Какие-то однодневные фреймворки в этом вашем IT...


    1. Einherjar
      04.10.2024 08:01

      Я напомню, что .NET 4.8 вышел в апреле 2018 года

      Какие-то однодневные фреймворки в этом вашем IT

      4.8 легаси уже был фактически на момент выхода, потому что то что тогда называли .NET Core уже активно параллельно развивался и всем было понятно что будущее за ним