Привет! Я Валерий Лаптев, руководитель разработки LM в России. За два года мне нужно было поднять огромный отдел, и это был довольно интересный опыт.
Дело в том, что «Леруа Мерлен» есть во многих странах. Головная компания — во Франции, называется ADEO. Там пишут код под Францию, Италию, Испанию и Россию. Бизнес-модели у нас разные: если на российском рынке мы держим минимальные цены (ниже всех конкурентов в мониторинге), то в Европе всё иначе. На самом деле отличий море — начиная от особенностей локали и заканчивая другим законодательством. Есть особенности инфраструктуры России (те же очень большие задержки до Хабаровска) и другой жизненный цикл оформления заказа. Всё это порождает вот такой адский код, состоящий из огромных блоков IF:
Два года назад у нас было 60 магазинов и много-много хотелок по фичам. Накатывались они примерно за полгода и не всегда правильно. Последней каплей после кучи отклонённых по низкому приоритету фич была просьба завести в заказ поле-строку, чтобы мы его уже потом сами парсили. Это нужно было для особенностей доставки в России, поскольку страна больше других стран присутствия LM. Нам отказали и в этом, точнее, сказали, что будет где-то через семь-восемь месяцев.
Полугодовой цикл неспешной головной компании нам не подходил. Естественно, мы предложили написать свой код, отдать на ревью и подождать внедрения… Правда, из этого ничего хорошего не вышло.
Почему фичи реализовывались медленно?
История очень простая: несмотря на свои десятки магазинов, мы не первые в мире. Есть потребности Франции (где головная организация), есть потребности других стран. Они приоритизируются по возможной прибыли или сокращению издержек для группы компаний и выполняются в этом порядке. То есть наши фичи делаются примерно почти никогда, разве что очень повезёт и в каком-то спринте кто-то закончит свою часть раньше и пойдёт разбирать низ бэклога.
Вторая особенность в том, что при накатывании любой фичи в мастер-ветку (вот в этот легаси-код на IF-IF-IF) нужно проверять, как она себя поведёт в других странах. Позволю себе цитату 441869 с Баша:
Программист: Ну представь, что ты писатель и поддерживаешь проект «Война и мир». У тебя ТЗ — написать главу как Наташа Ростова гуляла под дождём по парку. Ты пишешь — «шёл дождь», сохраняешь, вылетает сообщение об ошибке: «Наташа Ростова умерла, продолжение невозможно». Почему умерла? Начинаешь разбираться. Выясняется, что у Пьера Безухова скользкие туфли, он упал, его пистолет ударился о землю и выстрелил в столб, а пуля от столба отрикошетила в Наташу. Что делать? Зарядить пистолет холостыми? Поменять туфли? Решили убрать столб. Получаем сообщение: «Поручик Ржевский умер». Выясняется, что он в следующей главе облокачивается о столб, которого уже нет...
В общем, когда у нас внедряется что-то для российских касс, где-то в Бразилии у кого-то может отрикошетить.
Это означает очень большое покрытие тестами, долгие предрелизные процедуры и вообще нежелание поддерживать код, который стремительно разрастается. Поэтому, чем меньше фич — тем лучше. Но вы держитесь там.
Позиция в целом очень понятная, и я на месте головной компании именно так бы и делал. Потому что это рационально.
Решение проблемы
Первый подход был в лоб: мы предложили открыть нам код, чтобы делать туда пулл-реквесты. Предполагалось, что тут будет сидеть человек 10 разработчиков, которые быстро-быстро будут кодить бизнес-критичные функции, отдавать французам, те — тестировать по своей процедуре, и всё будет хорошо.
Собственно эти люди уже были: мы занимались тем, что выпиливали лишнюю бизнес-логику, доставшуюся нам от других стран типа разных накопительных скидок и необычных акций (которые просто невозможны при нашей бизнес-модели) и ставили на это место пустышки.
Французы в ADEO хотели релизный цикл за накатку и установку новых версий через себя. Приняли наше предложение про одну ветку для опытов.
Дали доступы, стали брать код на ревью. Оказалось, это всё равно медленно. Роллауты по нескольку месяцев — это не дело. Ну выиграли несколько недель, но всё равно процесс не подходил.
Потом шесть месяцев не выходила важная нам фича в контентной части (управление данными о товаре, которые видит клиент). Мы сидели шесть месяцев без релиза. То у них фича не шла, то тесты не прошли, то реализовали не совсем то, что нам нужно. В итоге долго сидели на ключевой системе без обновлений. Там были NodeJS + PostgreSQL + Couchbase + Elasticsearch + Angular на фронте. В коде из-за ряда археологических слоёв встретили вещи вроде неверного использования SQL-базы и нереляционной базы. В одном из мест брался огромный кусок мастер-данных, вставлялся в одно поле SQL-базы, а потом в NoSQL-базе разбивался на сущности. На одну страницу сайта с показом товара приходились десятки и сотни таких запросов. При дальнейшем чтении этого легаси волосы на разных частях тела начали шевелиться. Мы поняли, с какими особенностями наслоений легаси сталкивается головной отдел.
Собственная разработка
Первая идея была в том, чтобы делать фичи вместе. На месте, то есть во Франции. Поехали вчетвером во Францию и стали сидеть рядом с коллегами, чтобы разобраться во всём вместе и сделать как нужно нам.
Не работало. Всё равно всё было очень медленно.
Вторая идея была в том, чтобы сделать форк всего того, что уже есть, и постепенно его допиливать. Мы сели архитектурным комитетом, оценили перспективы, просчитали примерные планы развития и поняли, что нужно выбирать другой метод. Конкретно — да, делать форк, но не для развития имеющегося кода, а для того, чтобы разбивать монолит на части и ставить микросервисы там, где это нужно.
То есть мы планировали переписать целые блоки логики в виде своего кода. А для этого стали переключать часть сервисов на то, что могло бы быть сделано у нас. Начали набирать разработчиков. Тогда мы полностью следовали стеку головной компании — Java, Spring и всё рядом, вместо Couchbase была Монго (это похожая NoSQL-база).
По мере развития проекта поняли, что нужно делать много чего по-своему (потому что так быстрее и проще, чтобы не поддерживать ненужное нам легаси, в частности), и стали расширяться уже и на другие технологии. Тогда были Java 7, Wildfly (бывший JBoss) и SVN. Мы спросили, почему они не переходят на Java 8, GIT и Tomcat. Оказалось, они были бы не против, но через пару лет. А пока, родные, пишите на старом стеке. Так мы слово за слово и решили отделяться окончательно. Бизнес разобрался, в чём вопрос, какие плюсы и минусы есть, и всецело поддержал.
Почти сразу выкинули процентов 30 кода, написали вокруг много своих микросервисов. Из того, что не трогали, — это почти всё ядро транзакций бизнес-процессов по деньгам.
Естественно, первое, о чём мы подумали, — это про то, как разграничить области разработки. Про это я бы ещё рассказал отдельно, но в общих чертах схема вот такая:
Горизонталь — это бизнес-области. Например, всё, что касается отношений с клиентами (первая зелёная ячейка), — это одна область, и там набор приложений одного отдела. Такое разделение по целевой функции создаёт несколько дублей кода в разных местах и требует хорошей корпоративной шины (опять же — отдельный рассказ), но позволяет чётко находить концы и решать задачу до результата. Глядя на это почти через три года, могу сказать, что архитектура была выбрана правильно, но зная, что я знаю сейчас, всё же пару изменений я бы внёс.
Сейчас мы пришли к тому, что в общей структуре есть много фича-команд, которые составляют большие продуктовые команды. При этом в продуктовой команде — не только сами разработчики, но и дизайнеры, и представители бизнеса. Поскольку конечная цель любого ИТ-отдела компании — либо в увеличении скорости развития бизнеса, либо в снижении издержек за счёт автоматизации, нам нужны представители бизнеса внутри этих команд. Розница — это всё про ИТ. Нет ни одного процесса, который можно было бы назвать «неайтишным».
Фича-команда — это небольшая группа людей (обычно аналитик, тестировщик, разработчик бека и разработчик фронта, опс). Аналитик обычно играет роль владельца продукта либо на это место приходит человек из бизнеса. У владельца есть беклог, приоритет, задачи. Он их диктует разработке. Разработчик выбирает вариант реализации сам, обсуждая в команде, что и как будет сделано. У нас нет тимлидов для оценки задачи, кодревью и принятия решения. Все делают всё. Обычно более опытные в команде дают мнения, на которые многие готовы положиться. Но любой может принять решение. Конечно, бывают конфликты, когда два разработчика не могут договориться про реализацию фичи. Если конфликт перешёл на личности — нужна эскалация до руководителя. Но большая часть — это выбор решения по реализации. Тогда все стоят и рисуют около доски пока не найдут устраивающий всех вариант. Обычно получается быстро, но были случаи, когда и целый день спорили. Когда спор заходит в тупик, часто зовут арбитра — человека из другой команды, мнению которого все доверяют. Ему объясняют суть проблемы, он решает. В этом процессе спора в теории может участвовать даже джун или практикант, но я знаю всего пару таких случаев — обычно у джунов есть наставник, которого они слушают.
Пример фича-команды: есть у нас сервисная платформа, которая позволяет вместе с товаром купить услугу у подрядчика. Например, купил дверь — можно сразу в корзину положить и установку, чтобы независимый мастер приехал и сделал по нашему стандарту. Мы проверим и оплатим, дадим гарантию. Так вот, эта команда делает продукт, для этого пишет ИТ-решения и принимают бизнес-решения, меняют процессы в магазинах. Договариваются с подрядчиками. Там — владелец продукта от бизнеса, операционщик из магазинов, архитектор, разработчики, аналитики и тестировщик. Они сразу используют нашу корпоративную API-платформу для доставки всех данных туда-обратно и пишут микросервис. Такой подход — сразу операционщики и бизнес-люди в связке с разработчиками и маленькая команда — позволяет очень быстро делать продукт. Но, думаю, лучше они сами чуть позже расскажут, как это выглядит изнутри.
Изначально мы не хотели делать отдельных тестировщиков: был тренд, что разработчик должен либо идти по TDD-методологии, либо сам тестировать свой код до конца. На деле это оказалось не очень эффективно. Поначалу всё шло хорошо: написал — отвечаешь. Тесты нужны тебе для того, чтобы твоё приложение работало правильно. Но потом, чем больше становилось задач и приложений, тем было сложнее. Какие-то приложения отмирали, какие-то уходили на прод и не менялись месяцами. Стало тяжело писать тесты, поддерживать их и так далее. Аналитики в командах менялись. Относительно недавно договорились, что были неправы: тестировщики нужны. Но разработчики не перестают писать тесты и — иногда — делать TDD. Мы для себя осознали, что тесты, которые проверяют функционал (приложение работает правильно), и тесты, которые проверяют, что приложение работает в проблемных ситуациях, — это должны делать разные люди. И для второго нужны именно тестировщики, поскольку они покрывают возможные странные случаи не только юнит-тестами.
Сейчас чисто разработчиков 60 человек — бек, фронт, фуллстеки. Ещё есть аналитики, тестировщики и поддержка. И плюс дополнительно ещё семь девопсов. Но всё равно 200 планируемых людей из заголовка не набирается, поэтому мы сейчас ищем новых людей, потому что поле работы огромное. Вакансии есть на Моём круге, если что. То есть из разработки у нас сейчас 74 примерно из 200.
InnerSource
С учётом, что у нас много независимых команд только в России, и ещё есть команды, которые пилят что-то похожее во многих других странах, мы двигаемся в сторону иннерсорса. Это очень похоже на опенсорс внутри ограниченной группы людей.
В рамках группы ADEO всех подразделений по странам весь код лежит в облачном Гитхабе. Проект оформляется по единым правилам оформления. Ограничений по стилю, технологиям и инструментам нет. Когда у тебя открытый код и понятные правила оформления — любой разработчик на стеке может контрибьютить. Чтобы законтрибьютить тебе в код, нужно прочитать доку, клонировать репозиторий, внести правку, отправить пулл-реквест.
В настоящее время Бразилия, Россия и Франция очень активно используют эту общую базу.
Мы сейчас стараемся весь код подрядчиков (а у нас их очень много по разным направлениям) перенести в InnerSource. При анализе мы создали карту на две оси: техническая сложность перевода в режим иннерсора по одной оси и вторая ось, насколько перевод в иннерсорс вообще полезен. Если код уникальный и нужен только в одном месте — возможно, не надо его даже трогать. А вот если много команд используют этот участок — точно нужно.
Всё это в целом повышает культуру разработки. И ускоряет скорость работы нескольких команд, потому что на любую нужную тебе фичу можно написать мерж-реквест. Его аппрувит команда-владелец, а тестирует тот, кто контрибьютер. Одно из важных условий — наличие автотестов и описаний любого кода в репозитории.
Ещё немного нюансов
Когда начали, не было ничего вообще. Параллельно с разработчиками набирали девопсов. Сейчас девопс-услуги либо предоставляются как сервис (тем, кому нужно), либо в продуктовой команде есть собственный опс, который уже определяет, что и как.
Сборка делается в Jenkins, код прогоняется в Сонаре (точнее, уже SonarQube). Не прошёл Сонар — нет релиза. Тестировщики пишут автотесты, владельцы кода — функциональные тесты. База данных даётся как сервис инфраструктурщиками. Полноценное нагрузочное тестирование делается в редких случаях, поскольку структуры тестовой базы и основной отличаются: на препроде у нас хаотичные данные, а не обезличенные реальные (это один из шагов в будущем), поэтому накатывать надо нежно и не всё сразу.
Скоро должны поехать в Kubernetes (а часть новых продуктов вроде маркетплейса уже изначально там), как только разберёмся с планом перехода и договоримся по всем мелочам в инфраструктуре.
Мы с коллегами продолжим рассказывать про то, как какая часть работы устроена, потому что почти везде можно углубляться бесконечно. Ну а вы можете следить за нашим реалити-шоу (потому что всё только строится и быстро меняется) и делать ставки, облажаемся мы или нет.
Автор: Валерий Лаптев