История одного рефакторинга

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Медведь и утка разбираются, как договариваться о рефакторинге
Медведь и утка разбираются, как договариваться о рефакторинге

Привет, Хабр! Меня зовут Миша, я фронтенд-разработчик в Сравни. Сегодня расскажу историю об одном рефакторинге. Как мы сначала копили джентльменский набор: лишние запросы и библиотеки, спагетти из кода и обещаний, пелена гигабайт в Docker-билде и отсутствие времени даже на размышления. Потом рефакторили, а теперь стараемся не допустить повторения проблем. 

Самая сложная часть всего этого процесса оказалось не в той его части, где мы предполагали изначально. Отсюда и идея для этой статьи – подсветить частный опыт, который возможно натолкнёт на идеи для общего правила. Давайте обо всём по порядку.

Откуда вообще берётся рефакторинг 

Эта история началась примерно полгода назад, когда я пришёл в команду ОСАГО. Я нажал заветную кнопку для клонирования репозитория и увидел достаточно классическую картину. Это был проект, который тяжело вздыхал, но ещё подавал признаки жизни. Там была куча библиотек, зависимостей, компонентов, функций – значительная часть этого выглядела лишней. 

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

Роадмап улучшений
Роадмап улучшений

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

Типичный кейс – разработка новой версии анкеты ОСАГО. Специфика бизнес-процессов вокруг наших продуктов такова, что анкета – довольно важная штука. Пользователь выбирает нужные параметры, отвечает на уточняющие вопросы, а мы предлагаем в ответ варианты; например, конкретно в моём случае – предложения по автострахованию. 

Помогает ли эта важность писать чистый код для функциональности анкет? Тут нужно учесть, “как сложилось исторически”.

Изначально анкета была построена на нашей первой дизайн-системе, проект был полностью на styled-components. Потом сделали вторую версию анкеты на самописных формах, и это породило кучу проблем. 

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

Мы взялись за разработку новой версии анкеты, для ускорения разработки мы переиспользовали архитектуру и часть контроллера от предыдущей версии. Это оказалось фатальной ошибкой. В процессе запуска всплыли недочеты: косяки архитектуры, необходимость поддержки нескольких версий анкет, активное развитие новой версии, синхронизация хранилищ и так далее. 

В итоге всё вылилось в то, что цикломатическая сложность нашего проекта с каждым коммитом росла в геометрической прогрессии. 

Обидно! Вроде работа работается, какие-то боли устраняются, на Code Review никто не филонит, но проект по сути всё равно находится на невысоком уровне, а разработчики ни на секунду не покидают темпоральную ловушку с бесконечным техдолгом. 

Как мы продавали идею рефакторинга бизнесу

Вопросы есть, пора было искать ответы. Мы решили изучить следствия проблем, по ним выявить причину, составить план решения и с этим сходить к бизнесу. Я полетел в Питер к одному неравнодушному коллеге. Ключевая и самая продуктивная часть мозгового штурма выглядела примерно так:

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

Причина оказалась не самой оригинальной на свете. Проект нашей команды — по сути, стартап. Разработка ведется конвейерным потоком, перевести дух особо некогда, задачи переходят в тесты. В этот момент могут поменяться макеты, и пока ты вносишь правки, задача становится неактуальной и всё сносится. Времени на развитие инфраструктуры особо нет, времени на рефакторинг – тем более. Все новые фичи по-хорошему должны быть готовы вчера. Что-то в задачах делается на скорую руку, и так оно впоследствии и остается. 

Звучит жутко, но на каком-то этапе развития проекта это было ок.. 

В ходе мозгового штурма мы насобирали довольно много информации, но для похода к бизнесу одних проблем было мало, нужен был план по их устранению – туда мы включили собственно проблемы, причины и варианты решений. 

С нашим предложением мы собрались в уютной компании с продакт-оунером, delivery-менеджером и лидом – и стали думать. Переписывать весь проект изначально не было нашей задачей. Это могло бы решить проблемы с “наследством”, но потенциально порождало бы кучу новых вопросов. Наш план был составлен примерно на год, больший упор делался на рефакторинг. 

Однако лид команды и delivery-менеджер поддержали идею дать новую жизнь проекту – мы посчитали, что отказываться не пристало. Началась работа по созданию ОСАГО 2.0.

Перестройка процессов в общем и распределение ролей в частности 

На этом этапе истории давайте обратимся к жизненному циклу задачи. Нужно учитывать то, что задачу делает не один разработчик, но команда. И как она будет выполнена по части скорости и качества – зависит от работы, проделанной на каждом этапе цикла разработки. 

В качестве примера можно вспомнить Формулу-1, где процессы выстроены идеально и всё работает как единый слаженный механизм. Там счёт идёт даже не на секунды, а на доли секунд. Поэтому если мы хотим наладить процесс разработки, просто поправить один из пунктов не получится. 

Сейчас у нас ведётся работа по выстраиванию процессов по всем направлениям, но сегодня я сосредоточусь на этапе поддержки. Именно он по итогу оказался для нас самым сложным. Не продвижение идеи рефакторинга бизнесу, не проектирование новой архитектуры, но именно перестройка поддержки. 

На всякий случай: тут речь не о пользовательской поддержке, в духе того, что мы всей толпой пошли общаться с клиентами, но о поддержке кода, который мы создали, как разработчики. 

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

Так как мы смирились, что наш проект в рамках компании – “стартап”, и не всегда есть возможность и время на полноценную поддержку окружения в момент разработки, мы договорились с бизнесом на один человеко-день в спринте на технические задачи. Договорённость предполагала, что это не просто какой-то сферический день в вакууме, но полноценный процесс, в рамках которого мы заранее планируем задачи, а затем выполняем. Если нет задачи на планирование предстоящего спринта, тогда мы работаем дальше просто по целевым задачам. 

Следующий шаг – это разделение по ролям в команде. Выглядит это примерно следующим образом:

На всякий случай подчеркну, что это не вполне про должности, матрицу компетенций или зону ответственности в классическом понимании. Предназначение этой модели – разбить проект на некоторые области и выделить сотрудника, который в эту область будет погружен сильнее остальных, будет её развивать, следить за улучшениями, распространять знания на команду, описывать нужное в документации.

Один из плюсов такого разделения — появляется возможность быстрее получать экспертное мнение по тематическим вопросам. Плюс, так как мы обращаемся к конкретному человеку за информацией, то уменьшается риск срабатывания фактора “должен сделать непонятно кто из команды”. Такое случается: приходят люди из соседней команды, тегают всю команду, просят, например, сменить текст на какой-нибудь вьюшке. И вот четыре человека останавливают свою работу, смотрят этот текст, нового текста ещё нет, и вообще, все эти данные идут откуда-то из SEO, так что разработчики тут вообще не при чем. Но при этом все дружно теряют много времени. 

Описываемую модель разделения ответственности можно рассматривать как задел для индивидуального плана развития. При этом сотрудник развивается в направлении, не только интересном для себя, но и полезном для проекта. Также идёт развитие команды за счёт шаринга знаний. Учитывая темп разработки, не всегда есть возможность самому уследить за всеми изменениями вокруг, а тут есть выделенные люди, которые гарантированно этим займутся. 

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

А появление документации помогает делать более аккуратный онбординг, и соответственно, мы облегчаем вход в команду новым разработчикам и уменьшаем бас-фактор. 

Важно понимать, что как внедрение ролевой модели, так и остальные изменения – это комплекс мер, а не отдельно взятые независимые активности. Например, возьмём Code Review. Оно есть, работает, ускоряет разработку. Но чтобы не страдало качество, необходимо внедрить еще кучу вспомогательных процессов: более активное дизайн-ревью, эксперт-ревью и другое. 

Естественно, в этом подходе есть и минусы, и, возможно, один из главных побочных эффектов наших изменений – это всё не бесплатно. Любая поддержка, любое развитие требует времени. 

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

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

Мы примерно расписали архитектуру из документации, но помимо этого, нам была нужна схема взаимодействия компонентов. Конечно, всё казалось легко, пока не начали делать. В общем, у нас появилась модель инициализации и модель взаимодействия, на которой тоже далеко не всё было понятно. 

После долгих обсуждений и более детального разбора, на примере нашего лендинга мы собрали уже что-то более связное и наглядное:

Данная схема нам помогла более подробно погрузиться в итоговый вариант проекта, заранее подумать над некоторыми неочевидными моментами в слоях приложения. Ну и собственно, в таком виде человек в роли архитектора может описывать трудные для понимания места. При этом лучше, чтобы они были малоизменяемыми, потому что всё равно у нас уходит ресурс на поддержку. 

Что дальше планируем делать со всем этим хозяйством? Во-первых, дополнительно увеличить время на технические задачи до двух-трёх дней. Далее — закрепить и модифицировать имеющиеся процессы. Тут можно сравнить с диетой. Чтобы она помогала, нужно следовать ей постоянно. 

Прямые и побочные эффекты рефакторинга 

Итак, к чему мы пришли в результате всей этой истории? 

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

Второе — это неизбежность факапов. Рано или поздно происходит “та самая” встреча, на которой всё тайное становится явным. И лучше, конечно, чтобы у вас в тот момент был листок с планами, с предложениями, как чинить. А ещё лучше, чтобы все эти замечания и предложения вы уже освещали ранее. Гораздо разумнее реализовывать их в более спокойной обстановке, чем потом тормозить развитие бизнес-фичей и пытаться в объятиях пламени мостить из костылей дорогу в светлое будущее. 

Третье — это цели и планы. Они должны быть всегда. Как сказал Михаил Чигорин, сильнейший шахматист России XIX века, "лучше плохой план, чем отсутствие плана". В планах также должна быть прозрачность, как со стороны разработчика, так и со стороны бизнеса. Таким образом, можно подготовиться к каким-либо изменениям, например, архитектурным, и заранее найти баланс между временем на техдолг и на фичи. 

В-четвёртых, очень важно учиться слушать и слышать бизнес. Это поможет как в отношении предыдущего пункта про цели-планы, так и в нахождении каких-либо альтернатив. Да, непонимание между бизнесом и разработкой случается, но важно работать сообща. 

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

Как инженеры, при прочих равных условиях мы все всегда стремимся примерно к одному и тому же — стабильному и работающему продукту, балансу между скоростью и качеством развития. И по-человечески расстраиваемся, когда что-то идёт не так – копится легаси, бизнес не соглашается на какие-то наши идеи.

История нашего рефакторинга лично меня научила проще относиться к проблемам: то, что они случатся – вопрос времени; поэтому важно не только то, что мы делаем, чтобы не допустить что-то плохое, но и сколько пользы мы можем извлечь из неприятностей.

Источник: https://habr.com/ru/companies/sravni/articles/748714/


Интересные статьи

Интересные статьи

Четыре года назад я выпустил игру, в которой необходимо было строить цепочки электрических цепей и зажигать лампочки и светодиоды. На тот момент аналогов у игры не было (и до сих пор не появилось), а ...
Но знаете ли вы, что в России существует свой «Genius Games», это издательство выпустило уже шесть игр (и скоро выпустит седьмую) и не планирует сбавлять обороты в части семейных научных «настолок»? О...
В 2015 году, когда я пришёл на своё текущее место работы, мне было непривычно от необыкновенной свободы действий. Буквально, на новом месте можно было проявить весь творческий потенциал как DevOps-ева...
11 февраля 2011 года Nokia опубликовала новую стратегию и заключила соглашение о сотрудничестве с Microsoft. Операционная система Windows Phone была выбрана в качестве ...
Холивар. История рунета. Часть 1. Начало: хиппи из Калифорнии, Носик и лихие 90-е Холивар. История рунета. Часть 2. Контркультура: пАдонки, марихуана и Кремль Холивар. История рунета. Часть 3. ...