Привет, Хабр! Я Леша Половинкин, работаю руководителем Python-разработки в AGIMA. Сегодня сказ будет о том, как разработать в очень короткие сроки с нуля классифайд для авто (а попросту огромную доску объявлений с кучей прикрученных к ней сервисов) и совершить те ошибки, которые неизбежны.  Так как мы занимаемся заказной разработкой, то видим разные проекты на совершенно разных стадиях готовности от нуля до «заберите этот легаси и дайте что-нибудь нормальное».  Mycar.kz — офигенный и мощный проект, который мы пилили продуктовой кросс-функциональной командой из 36 человек. Но об этом я подробно расскажу чуть ниже. Итак, наш заказчик хотел создать у себя на родине (в Казахстане), новый классифайд — ресурс с объявлениями от юридических и физических лиц по продаже и покупке автомобилей. Это должен быть не просто сайт, а именно продукт: веб и мобильные приложения под две платформы.  Еще в начале февраля 2020-го года мы познакомились, поели конины (прости, Господи) и прогулялись по вершине Чимбулака, а уже через пару дней мы начали подбирать команду аналитики и дизайнеров, чтобы успеть в 2020-м сдать проект целиком. Так оно и вышло, но все не так просто, как кажется, и как обычно пишут в статьях. Необходимо было:   разработать брендинг, нейминг, придумать концепцию,  отрисовать мобильные приложения и веб-версию с адаптивом,  подготовить инфраструктуру, ну и успеть реализовать frontend, backend и мобильные приложения.  Планировалось, что классифайд займет значимую нишу рынка Казахстана. Поэтому как и всегда ударить в грязь лицом нельзя.   Поскольку это крупный проект, то им нельзя было заниматься силами 2-3 специалистов. Мы сформировали несколько команд: Всего были вовлечены силы 36 человек.    Поскольку трафик на проекте планировался большой, целей у проекта много и останавливаться он не планировал ни на минуту, мы остановились на сервисной архитектуре реализации.   Это вносило дополнительные сложности в настройку инфраструктуры и добавляло проблем с реализацией, но позволяло сразу грамотно управлять данными и избежать проблем с «растаскиванием» монолита на куски. Как и в любой архитектуре, сервисная имеет свои плюсы и минусы, об этом косвенно мы писали в одной из статей ранее.    Мы разбили проект на множество сервисов, каждый из которых занимался выполнением своих конкретных задач. Давайте разберем несколько из них:   Сервис объявлений самый крупный. Он содержит в себе функциональность по созданию, редактированию, публикации, поиску объявлений, все необходимые структуры данных, а также базу авто и сопутствующие API.  Сервис SEO обеспечивает умную настройку правил формирования URL, а также конфигурирование пререндеринга: все в удобном администраторском интерфейсе.  Сервис замазывания номеров. ML-решение, которое быстро распознает номера и обеспечивает их скрытие. Сервис кредитов обеспечивает расчет кредитов для объявлений в реальном времени. Сервис трейд-ин, позволяет продать автодилеру за счет интеграции с CRM-системой. В целом, сервисов получилось много, для самых различных задач — ведение блога, хранение истории поисков, избранного, профилей пользователей, сервисы для финансовых программ, маркетинговых активностей, геолокации.   Микросервисная архитектура завернута в Kubernetes. Для каждого из них есть свой deployment (через helm), он поднимает replica-set, в котором по 3 инстанса (на каждой ноде по 1 штуке), переменные окружения тянутся из secret’ов, создание которых также обеспечивает helm. Кластер Postgresql на трех отдельный виртуальных машинах, для управления кластером используется patroni. Подключение к Postgresql осуществляется через haproxy, т.к. у хостинг-провайдера еще не были готовы к эксплуатации облачные балансировщики, а Mongo работает как контейнер на трех отдельных серверах в кластере. RabbitMQ поднят кластером.    Отдельно стоит сказать про CI. Мы использовали Gitlab CI/CD — merge (или commit) в ветки, выделенные под контур, триггерит его, после чего инициируется создание обновленных docker image, а затем они кладутся в image storage и запускается helm upgrade, который запускает процесс деплоя.  И на все про все у нас было 6 месяцев. Это очень мало, поэтому я бы хотел подчеркнуть, с какими проблемами мы столкнулись, чтобы вы их не повторяли.  Запуск MVP планировался на середину лета 20 года.  Изначально в него были определены: Каталог автомобилей с фильтрациями и сортировками.  Личный кабинет пользователя с возможностью управлять объявлениями: публиковать, изменять и удалять. А также добавлять понравившиеся авто в избранное.  Сохранение настроек поиска автомобилей и настройка уведомлений о новых объявлениях по нему. Настройка авторизации-регистрации пользователя. Этот бэклог включал в себя парсинг данных об автомобилях, а также панели администратора, чтобы была возможность модерировать объявления и управлять контентом.  Уже на этапе близком к дедлайнам, мы согласились включить в проект еще 3 довольно объемных блока работ: Блок статей, куда менеджеры заказчика смогли бы добавлять новости и заметки по миру авторынка. Раздел с кредитными программами по новым авто и авто с пробегом, а также функция отправки заявки на кредит с интеграцией со скорингом. Брендовый раздел каталога Mycar Prime: только проверенные авто с пробегом от дилера. На реализацию у нас оставалось примерно полтора месяца, хотя по ним не была готова аналитика и не был отрисован дизайн.   Наверное, это один из самых больших просчетов, что мы совершили.  Архитектурный план мы выдержали весьма неплохо. Мы с самого начала определили все главные компоненты, которые нужно было вынести в сервисы. Того же не получится сказать по поводу переработок интерфейса.  Старт бэкэнда произошел еще до готовности дизайна. Наша цель была успеть предоставить максимальное количество готовых API до старта разработки frontend и отладить интеграционные потоки в архитектуре. Все ради экономии времени. По итогу, разработчикам backend приходилось постоянно возвращаться к ранее созданным интерфейсам, переделывать компоненты, переписывать API, это происходило из-за довольно серьезных изменений интерфейсов на дизайне, которые не невозможно было учесть в нашем кейсе при формализации задачи.  Нам необходимо было соблюсти всю последовательность производственных процессов и до появления интерфейсов для пользователей не разрабатывать интерфейс интеграционных потоков. Было несколько моментов, когда приходилось изменять ER-модель данных в уже готовом сервисе, а следом за ним и весь каскад API. Сложнее всего становится, когда после этапа аналитики весь сервис целиком меняет свою суть. Одной из основных задач всего проекта было упрощение взаимодействия между дилерскими центрами клиента и новой командой классифайда. Нам нужно было настроить интеграцию между мастер-системами клиента и нашей системой.  Мастер-системы находились в процессе разработки в начале самого проекта. Это вызвало дополнительные сложности. Наши базовые сервисы выстраивались только на теории, поскольку готовых endpoint еще не было, что привело к сложностям и дополнительным итерациям доработок самих сервисов. К примеру, оказалось, что данные в мастер системах сильно отличаются от требуемых в классифайде. Приходилось экстренно в режиме брейншторма находить решение с обеих сторон.  Одним из решений, как этого можно было избежать — не торопиться с выпуском в продакшен самих сервисов. Необходимо было подготовить каркас сервиса, реализовать объектную модель, но не реализовывать саму интеграцию до момента, пока нам не предоставят API. Таким образом, после получения спецификаций на интеграцию, нам потребовалось бы реализовать 1 сервис интеграции, который подготавливал бы данные для сохранения в мастер-системы классифайда. Это сдвинуло бы сроки интеграции, но общий срок по реализации оказался бы не изменен. Этот пункт напрямую выходит из предыдущих. Мы все время смотрели только на дедлайн, не замечая, что упускаем довольно много мелких и важных вещей. Вместе с заказчиком, мы пытались выжать все возможное из процесса разработки, что приводило к обратному эффекту. Спешка не давала нам времени на отладку и исправление мелочей на фронтах, потоки интеграции шли нестабильно и выбивались с пограничных значений. В надежде, что менеджеры клиента будут иметь опыт работы с какой-либо панелью администратора, мы отказались от кастомной панели администрирования, и это стало большой ошибкой. Мы отказались от проектирования интерфейса и взяли готовую панель. Это привело к сложностям адаптации менеджеров и затянуло сроки насыщения контентом проекта. В конце концов эту проблему удалось пофиксить за счет написанных инструкций и обучения контент-менеджеров. Но дедлайн приближался, а седых волос становилось все больше. Отказ от тестов был вынужденным, потому что дедлайны горят, проект выпускать нужно, а автотесты съедают львиную долю часов разработчика. Конечно, любой компонент необходимо покрыть несколькими тестами, чтобы убедиться, что разработчик не потерял граничные значения, компонент делает что должен и т.д.  В ситуации близкого дедлайна, нам пришлось отказываться от всего, что могло повлечь сдвиг сроков. И автотесты были одними из первых. Сэкономленное на них время планировалось потратить на снижение рисков и увеличение сроков отладки.  Но привело это к обратному процессу. Изменения API влияли на мобильные устройства. Происходили постоянные краши устройств, приходилось постоянно перепроверять большое количество интерфейсов. Тесты позволили бы снизить количество багов и удешевить процесс интеграции бэкенда с фронтами.  Наиболее явно это стало на интеграции потоков данных между системами. В какой-то момент для работы классифайда потребовалось подружить два разных набора данных по автомобилям и комплектациям. Это привело в необходимости перевести все существующие объявления на новый формат данных. В процессе отладки интеграции приходилось постоянно проверять парсинг данных, сериализацию и валидации.  Проверка и отладка занимала уйму времени, т.к. backup данных был весьма тяжелым. Внедрение автотестов позволило бы работать не с объемными данными, а с небольшими unittests, которые позволили бы убедиться в корректности небольших участков интеграции и сэкономили бы уйму времени.  Поскольку основной пользователь — житель Казахстана, нам необходимо было использовать казахстанских провайдеров, и использовать их мощности для разворачивания инфраструктуры. Это вызвало неожиданные проблемы, на решение которых потребовалось колоссальное количество времени.  Не оптимальный VPN, инфраструктурные проблемы провайдера, нестабильный интернет, государственный фаервол.  Это и еще тысячи мелких проблем вызывали сильные смещения сроков по настройке инфраструктуры и CI/CD, что в свою очередь не позволяло полноценно реализовывать классифайд.  Я укажу лишь самые болезненные для нас пункты. Государственный фаерволл блокировал зеркала пакетов для сборок backend, frontend и mobile.  VPN иногда просто не позволял отправлять запросы и вызывал сбои с загрузкой статики. Скорость скачивания пакетов оставляла желать лучшего, что приводило к 40 минутам на деплое новых сервисов.  Постоянно отваливающийся интернет, что влияло как на CI/CD, так и на доступность контуров. В совокупности, эти факторы приводили к долгому и нервному решению проблем разработки и инфраструктуры.    По итогу, DevOps потратили огромное количество времени на настройки инфраструктуры, зазвонили до дыр все телефоны провайдера, жили этими серверами несколько недель.  Вероятно, нам необходимо было отказаться от использования казахских провайдеров на первых этапах, когда мы поняли, что проблем будет очень много. Вместо этого мы упорно продолжали «жрать кактус», вместого того, чтобы предложить клиенту сервера наших партнеров. На их инфраструктуре мы могли бы запустить MVP, подготовить все стенды, отладить весь проект, после чего запустить этап миграции инфраструктуры. На этапе MVP такого рода простои оказались весьма дорогостоящими.  Под дедлайны нам удалось запуститься, иначе бы этой статьи не случилось :)  Приложу пруфы: сайт, МП iOS, МП Android. Мы успели выкатить все функциональности, о которых договаривались с заказчиком, хоть и часть команды немного поседела. Проект получился очень мощным и стабильным. А главное — мы передали всю экспертизу, которую получили на проекте, заказчику. Так, с трех стейкхолдеров, команда разрослась до 45 человек. И мы совместно с ними развиваем проект дальше, наполняем фичами и поддерживаем микросервисы.   Чтобы не быть голословным, что проект действительно получился крутым, мы собрали несколько наград на российских конкурсах: Золотой Сайт и Приложение, а также конкурсе Tagline. Расскажите в комментариях, с какими проблемами вы сталкиваетесь, когда нужно уложиться в горящие дедлайны.