Ощущения смерти, одиночества, в то же время безумная жажда к жизни… Вы могли бы подумать, что мы решили устроить лекцию по экспрессионизму и погрузить вас в творчество Мунка. Но нет. Все эти этапы ты переживаешь в момент, когда видишь, что твой технический долг скоро столкнёт твою компанию в бездну кризиса.
За 8 лет IT-команда Dodo Pizza выросла с 2 разработчиков, обслуживающих одну страну, до 80 человек, обслуживающих 12 стран. Три года назад я пришел в Dodo Pizza в качестве Chief Agile Officer и стал помогать командам создавать процессы и внедрять инженерные практики. Зачастую эти внедрения было слишком медленными. Кроме того, обнаружилось, что когда несколько команд работают над одним продуктом, сложно заставить их поддерживать высокое качество кода.
Мы гнались за развитием бизнес-функций, отложив на потом техническое совершенство кода. Так мы оказались в западне. Огромный технический долг занес над нами кулак, но не раздавил, а всего лишь, щелкнув пальцами, сбросил нашу компанию в пучину кризиса. В 2018 году команда маркетинга запустила массовую рекламную кампанию, мы не выдержали нагрузки и упали. Позор, стыд и срам. Но во время кризиса, мы поняли, что можем работать во много раз эффективнее. Кризис заставил нас быстро внедрить самые известные инженерные практики и совершить революцию в процессах.
Background
Dodo Pizza – это компания-киборг, которая продает пиццу. Наш бизнес основан на платформе Dodo IS, которая управляет всеми бизнес-процессами: приём заказов, приготовление пиццы, управление запасами, управление людьми (менеджмент) и многое-многое другое. Всего за 8 лет мы выросли с 2 разработчиков, обслуживающих одну пиццерию, до 80 + разработчиков, обслуживающих 498 пиццерий в 12 странах мира.
Три года назад Dodo IS была монолитом, содержащим 1 миллион строк кода. Было небольшое покрытие unit-тестами, API/UI-тестов не было вовсе. Само качество кода было разочаровывающим. Все об этом знали или хотя бы догадывались. В мечтах о светлом будущем мы раскалывали монолит на дюжину сервисов и переписывали самые отвратительные части системы. Мы даже нарисовали диаграмму «будущей» архитектуры, но, честно говоря, так ничего и не сделали, чтобы приблизиться к ней.
Чем больше росла команда, тем больше мы страдали от отсутствия четкого процесса и инженерных практик. Релизы становились все больше и больше, потому что все шесть команд разработчиков одновременно вносили изменения в разные ветки. Когда команды мержили свои изменения в одну ветку, мы порой теряли до 4 часов, пытаясь разрешить конфликты слияния. Автоматических регрессионных тестов не было, и с каждым релизом мы тратили все больше времени на ручной регресс.
Shit happens
В 2018 году команда маркетинга запустила нашу первую федеральную рекламную кампанию на ТВ с бюджетом 100 млн. рублей. Это было большое событие для Dodo Pizza. IТ-команда тоже хорошо подготовилась к кампании. Мы автоматизировали и упростили наш деплой – теперь с помощью одной кнопки в TeamCity мы могли развернуть монолит в 12 странах. С помощью тестов производительности мы провели анализ уязвимостей. Мы сделали все возможное, но всё равно облажались.
Рекламная кампания была потрясающей. Мы получали от 100 до 300 заказов в минуту. Это была хорошая новость. Плохая новость: Dodo IS не выдержала такой нагрузки и умерла. Мы достигли наших вертикальных пределов масштабирования и больше не могли обрабатывать заказы. Система перезагружалась каждые 3 часа. Каждая минута простоя стоила нам потери уважения со стороны разъяренных клиентов.
Когда я пришел в Dodo Pizza три года назад, я сразу же начал внедрять инженерные практики. Большинство команд приняли парное программирование, модульное тестирование и DDD довольно быстро. Но не все было так просто. Мне пришлось преодолевать сопротивление разработчиков, продактов и команды саппорта.
В отличие от идей инженерных практик, не все поддерживали идею feature teams. Разработчики привыкли думать, что команда, сосредоточенная на одном компоненте, пишет лучший код. Было неясно, как совместить быстрое развитие бизнес-функций с давно назревшим массовым рефакторингом сложной системы. Еще этот бесконечный поток багов постоянно требовал внимания… Мы выпускали продукт не чаще одного раза в неделю, и каждый релиз занимал довольно много времени, требовал огромного количества ручного регресса и поддержки UI-тестов. Я пытался исправить это, но изменение процесса шло слишком медленно и фрагментарно.
История падения и подъема
Initial state: монолитная архитектура
В погоне за скоростью развития бизнес-функций мы не всегда хорошо продумывали технические решения. Недостаток опыта сказался на нас. У нас было монолитное приложение с единой базой данных, содержащей все данные из всех компонентов в одном месте. Трекер, проверка, сайт, API для целевых страниц – все компоненты системы работали с единой базой данных, что создавало препятствия. Наша монолитная архитектура создавала монолитные проблемы.
True story
Монолитная архитектура хороша для начала, потому что она проста. Но она не может выдержать высокую нагрузку будучи единственной точкой отказа. Однажды все наши рестораны в России перестали принимать заказы из-за сообщения в блоге. Как такое могло случиться?
Наш генеральный директор — Федор опубликовал пост в своем блоге. Этот пост быстро завоевал популярность. На сайте блога Федора есть счетчик, показывающий количество пиццерий нашей сети и общий доход всех пиццерий. Каждый раз, когда кто-то читал блог Федора, веб-сервер отправлял запрос в master базу данных для расчета выручки. Эти запросы настолько перегрузили базу данных, что она перестала обслуживать запросы из кассы ресторана. Мы быстро исправили проблему, но это был явный признак (среди многих других), что наша архитектура не в состоянии удовлетворить потребности бизнеса и должна быть переработана. Но мы продолжали игнорировать эти знаки.
Ранний сбой в 2018 году
14 февраля. Для любителей поздравить друг друга 14 февраля мы делаем специальную пиццу – «Пепперони» в форме сердца. Я навсегда запомню 14 февраля 2018 года, потому что в этот день, когда все пиццерии работали на полную загрузку, Dodo IS начала падать. В каждой пиццерии стоит 4-5 планшетов для отслеживания того, для какого заказа пиццемейкер делает тесто, кладет ингредиенты, выпекает или отправляет на доставку. На тот момент количество пиццерий достигло 300+, каждый планшет обновлялся несколько раз в минуту. Все эти запросы создали такую огромную нагрузку на базу данных, что она перестал выдерживать и начала отказывать. Dodo IS умерла во время пика продаж. Впереди был напряженный праздничный сезон: 23 февраля, 8 Марта, 1 и 9 Мая. Во время этих праздников мы ожидали еще большего роста заказов.
День, когда ты умрешь. Зная наши планы роста и предел нагрузки, которую мы можем выдержать, мы выяснили, как долго мы можем оставаться в живых. Предполагаемая дата Армагеддона ожидалась примерно через полгода – в августе или сентябре 2018. Каково это – жить, зная дату своей смерти?
Остановить разработку функций на год. Вместе с генеральным директором Федором мы должны были принять трудное решение. Пожалуй, одно из самых сложных решений в истории компании. В течение следующего года мы сделали только одну бизнес-функцию. В остальное время команды занимались гашением технической задолженности. Этот долг обошелся нам очень дорого – более 100 млн. рублей.
Некоторые улучшения после года
За год мы заметно выросли:
- Мы автоматизировали и ускорили процесс деплоя до 4-5 часов
- Наконец-то мы начали распиливать монолит: трекер и TV-борды были вынесены на отдельный сервис со своей собственной базой данных
- Мы начали отделять кассира доставки – второй компонент, создававший высокую нагрузку
- Переписали систему аутентификации пользователя и устройства
Казалось бы, мы могли гордиться собой. Но впереди нас ожидало огромное разочарование.
Провал во время Федеральной маркетинговой кампании. Второй кризис доверия
Технический долг легко накопить, но очень трудно погасить. Вряд ли вы сможете заранее понять, во сколько это вам обойдется.
Несмотря на то, что мы целый год боролись с техническим бэклогом, мы не были готовы к массовой маркетинговой кампании и облажались перед нашим бизнесом снова. Доверие, заслуживаемое каплями, терялось ведрами.
Под нагрузкой Федеральной маркетинговой кампании мы снова легли. Система упала и перезагружалась каждые 3 часа. Наш бизнес потерял десятки миллионов рублей.
Благодаря кризису, мы узнали, что в экстремальных условиях можем работать во много раз эффективнее. Мы релизили по 20 раз в день. Все работали, как одна команда, сосредоточившись на одной цели. В течение двух недель кризиса мы делали то, что боялись начинать делать раньше, полагая, что на это уйдут месяцы работы. Асинхронный прием заказа, нагрузочные тесты, чистые логи – это лишь малая часть того, что мы сделали. Мы хотели продолжать работать так же эффективно, но без сверхурочных и стресса.
Вынесенные уроки
После ретроспективы мы полностью перестроили наши процессы. Мы взяли LeSS за основу и дополнили его инженерными практиками. В течение следующих нескольких месяцев мы сделали прорыв во внедрении инженерных практик. Основываясь на LeSS, мы внедрили и продолжаем использовать:
- Единый бэклог продукта
- Полностью кросс-функциональные и кросс-компонентные команды
- Парное программирование
- Мобильная разработка
- Настоящая непрерывная интеграция (CI) – непрерывная интеграция кода из 9 команд в одну ветку
- Упрощенная работа с ветками (trunk-based development)
- Частые релизы: непрерывный деплой для микросервисов, релиз каждый день для монолита
- Отказ от отдельной команды QA, эксперты QA являются частью команд разработки
6 практик, которые мы выбрали после кризиса:
1. Сила фокуса. До кризиса каждая команда работала над своим собственным долгом и специализировалась в своей области. Во время кризиса у команд не было конкретных задач, у них была одна большая сложная цель. Например, мобильное приложение и API должны обрабатывать 300 заказов в минуту, несмотря ни на что. Лишь от команды зависит, как эта цель будет достигаться. Команды сами формулируют гипотезы и быстро проверяют их на проде. Команды не хотят быть простыми кодерами, они хотят решать проблемы.
Сила фокуса проявляется в сложных задачах. Например, во время кризиса мы создали нагрузочные тесты, несмотря на то, что у нас не было опыта. Мы также сделали логику получения заказа асинхронной. Мы долго думали об этом и говорили, и нам казалось, что это очень сложная задача, которая может занять много времени. Но оказалось, что команда вполне способна сделать это за 2 недели, если ее не отвлекать и полностью сосредоточиться на проблеме.
2. Внутренние хакатоны. Мы провели хакатон «500 ошибок». Все команды дружно очистили журналы и удалили причины 500 ошибок на сайте и в API. Целью было сохранить логи в чистоте. Когда логи чисты, новые ошибки хорошо видны, вы можете легко настроить пороговые значения для оповещений.
Еще один пример хакатона – баги. Раньше у нас был полный бэклог багов, некоторые из них болтались там в течение многих лет. Казалось, они никогда не закончатся. И каждый день появлялись новые. Мы объединили работу над багами и обычными элементами бэклога.
- Если баг находится в бэклоге более 3 месяцев, просто удали его. Он провалялся там уже целую вечность, и никто не умер.
- Оцени боль, которую причиняют оставшиеся баги клиентам. Оставь только те баги, которые усложняют жизнь большой группе пользователей.
- Устрой внутренний хакатон по багам. Мы сделали это за несколько спринтов. Каждый спринт каждая команда брала несколько ошибок и исправляла их. После 2-3 спринтов у нас был чистый бэклог. Теперь можно ввести #zerobugspolicy.
- #zerobugspolicy. Если баг попадёт в бэклог, он будет исправлен. Любая ошибка в бэклоге имеет более высокий приоритет, чем любой другой элемент бэклога. Но для того, чтобы попасть в бэклог, ошибка должна быть серьезной. Либо она наносит непоправимый вред, либо затрагивает большое количество пользователей.
3. От проектных групп до стабильной команды. Была забавная история с проектными командами. Во время кризиса мы сформировали экспертные команды людей, которые были наиболее квалифицированными для задачи. После того, как кризис закончился, команды решили продолжить эту практику. Несмотря на то, что эта идея мне совсем не понравилась, мы попробовали. Всего за 2 недели (один спринт), на следующей ретроспективе, команды отказались от этой практики, (это решение меня осчастливило). Если команде не хватает некоторых навыков, они могут постепенно учиться. Но командный дух, поддержка и взаимопомощь формируются очень долго, на это уходят месяцы. Краткосрочные проектные команды постоянно находятся в стадии форминга и шторминга. Вы можете потерпеть это в течение нескольких недель, но вы не можете работать так все время.
4. Нет ручному регрессу. Мы поставили перед собой цель избавиться от ручных регрессий. Нам потребовалось 1,5 года, чтобы достичь ее. Но наличие долгосрочной амбициозной цели заставляет думать о шагах, ведущих к цели.
- Автоматизация критического пути.
В июне 2017 года, мы сформировали команду QA. Задачей команды было автоматизировать регресс наиболее критичного функционала Dodo IS – прием и производство заказов. В течение следующих 6 месяцев новая команда QA из 4 человек охватила весь критический путь. Разработчики Feature teams активно помогали им. Вместе мы написали красивый и понятный доменный язык (DSL), который понимали даже клиенты. Параллельно со сквозными тестами разработчики обвешивали код модульными тестами. Некоторые новые компоненты были переработаны с помощью TDD. После этого мы распустили команду QA. Бывшие члены команды QA присоединились к группам, работавшим над функциями, чтобы поделиться опытом поддержки и обслуживания автотестов. - Теневой режим.
Имея автотесты, во время 5 релизов мы делали ручные регрессии в теневом режиме. Команды полагались только на автоматическое тестирование, но, когда команда решала, что она готова к релизу, мы запускали ручной регресс, чтобы проверить, не пропустили ли наши автотесты какие-либо ошибки. Мы отслеживали, сколько ошибок было поймано вручную и не поймано автотестами. После 5 релизов мы рассмотрели данные и решили, что можем доверять нашим автотестам. Никаких серьезных ошибок не было пропущено. - Отказ от ручных регрессий.
Когда у нас было достаточно тестов, чтобы доверять им, мы полностью отказались от ручного тестирования. Чем больше мы проводим тестов, тем больше им доверяем. Но это произошло только через 1,5 года после того, как мы начали автоматизировать регрессионное тестирование.
5. Тест производительности – часть регрессионного теста. Во время кризиса мы сделали набор тестов производительности. Это было совершенно новым для нас опытом. Тем не менее, всего за 2 недели нам удалось создать кое-что с помощью инструментов Visual Studio. Мы использовали их и для увеличения искусственной нагрузки на сервер, чтобы определить пределы производительности. Например, если органическая производственная нагрузка составляет 100 заказов/мин, мы добавляли еще 50 заказов/мин с помощью наших тестов, чтобы посмотреть, могут ли производственные серверы обрабатывать увеличенную нагрузку.
На следующий год мы передали тесты производительности опытной команде PerformanceLab. Теперь мы проводим эти тесты еженедельно и предоставляем быструю обратную связь командам разработчиков, если что-то влияет на производительность.
6. Инженерные практики. Все наши команды используют парное программирование. Я считаю парное программирование одной из самых простых, но мощных методов. Если вы не знаете, с какой инженерной практики начать, я рекомендую парное программирование.
Результаты
Главный результатом для нас стала встряска. Мы проснулись и начали действовать. Кризис помог нам увидеть максимум наших возможностей. Мы увидели, что можем работать во много раз эффективнее и быстрее достигать поставленных целей. Но для этого необходимо изменить привычный способ работы. Мы перестали бояться смелых экспериментов.
В результате этих экспериментов за последний год мы значительно улучшили качество и стабильность Dodo IS. Если во время весенних каникул 2018 года наши пиццерии не могли работать из-за Dodo IS, то в 2019 году, с ростом от 300 до 498 пиццерий, Dodo IS работает безупречно. Мы спокойно пережили пик продаж в новом году, во время Второй маркетинговой кампании и весенних праздников.
Впервые за долгое время мы уверены в качестве системы и можем себе позволить крепко спать по ночам. Это результат постоянного использования инженерных методов и концентрации на техническом совершенстве.
Результаты для бизнеса
Инженерные практики не нужны сами по себе, если они не приносят пользу вашему бизнесу. В результате концентрации на техническом совершенстве мы улучшаем качество кода и разрабатываем бизнес-функции с предсказуемой скоростью. Релизы стали для нас регулярным событием.
Результаты для команд
Сегодня мы используем широкий спектр инженерных методов:
- Полностью кросс-функциональные и кросс-компонентные команды
- Парное программирование/Мобильная разработка
- Genuine Continuous Integration – непрерывная интеграция кода из 9 команд в одну ветку
- Единая цель для нескольких команд
- Subject Matter Expert в команде
- Нет отдельной команды QA, эксперты QA являются частью команд разработки
- Замена ручного регресса автотестами
- Политика отсутствия багов (#Zerobugspolicy)
- Stop the Line в качестве драйвера для ускорения деплоя пайплайна
Чему мы научились
Я хотел бы не допустить кризиса. Как разработчик, я чувствовал личную ответственность за накопление слишком большого технического долга и за то, что не смог предвидеть последствий.
- Инженерные практики защищают бизнес от кризиса
- Не накапливать технический долг. Может стать слишком поздно и стоить слишком дорого
- Эволюционные изменения занимают в несколько раз больше времени, чем революционные
- Кризис – это не всегда плохо. Используйте кризис для революционизации процессов
- Тем не менее, длительная эволюционная подготовка требуется заранее
- Не применяйте слепо все методы, которые вам нравятся. Некоторые методы ждут своего часа, и когда он придет, команды будут использовать их без сопротивления. Ждите подходящего момента
- Со временем команды сами начинают принимать важные решения и реализовывать их. Дайте им благоприятную среду, чтобы попытаться, позвольте потерпеть неудачу и учиться на ошибках
Технический долг привел нас к жуткому кризису. Я очень рад, что наша команда нашла в себе силы использовать эту патовую ситуацию как точку роста. На собственной шкуре мы поняли, что время кризис можно и нужно использовать для массовых организационных и технологических изменений. Так что никогда не опускайте руки, ведь даже в самой сложной ситуации есть место для подвига.
Благодарности
Я хотел бы сказать большое спасибо всем людям, которые помогли мне в моем путешествии от кризиса к трансформации LeSS. Я постоянно чувствую вашу поддержку.
Большое спасибо нашему генеральному директору Федору Овчинникову за доверие. Вы настоящий лидер компании с подлинной гибкой культурой.
Большое спасибо Дмитрию Павлову, нашему Product Owner'у, моему старому другу и со-тренеру.
Спасибо Александру Андронову и Андрею Моревскому за поддержку.
Большое спасибо Даше Баяновой, нашему первому штатному Scrum-мастеру, которая всегда помогает и поддерживает меня со всей нашей инициативой. Вашу помощь трудно переоценить.
Отдельное огромное спасибо Джоанне Ротман, которая помогала мне писать этот отчет в любом состоянии: находясь в отпуске, выздоравливая после болезни. Джоанна, было очень приятно работать с тобой. Ваша помощь, советы, внимание к деталям и трудолюбие очень ценны.
Автор: bevzuk