Когда начинается новый проект — его код чист и прекрасен. Самое время проектировать красивые абстракции, писать хорошие интерфейсы и профессиональные реализации. Жизнь прекрасна! Наш проект тоже.
Мы продолжаем добавлять функционал, всё идёт гладко. Потом в некоторый момент нам приходится немного срезать угол, чуть-чуть свернуть с намеченной дорожки, добавить совсем-совсем маленькую обработку одного частного случая… Нет-нет, никаких «костылей»! Просто немного необходимого кода, приближающего красивую теорию к работающей практической реализации. Ничто не предвещает беды и разработка идёт достаточно бодро.
Тем ни менее, на полотне нашей идеальной картины кода всё-же возникают небольшие кляксы. Некоторые люди называют их «техническим долгом». Это не означает, что вы действительно кому-то что-то задолжали: это просто не очень хороший код. Но он как-то работает, решает свои задачи.
По мере продолжения разработки мы будем натыкаться на подобные места в коде всё чаще и каждый раз у нас будет выбор: броситься грудью на амбразуру и переписать всё начисто или обойти проблемное место ради решения другой задачи (той, над которой вы работаете в данный момент). Иногда мы бросаемся в бой, но всё-же чаще мы выбираем вариант с обходным путём.
В каждом отдельном случае это замедляет нас лишь немного. Но, поскольку по мере приближения дедлайна требования к скорости разработки лишь растут, нам приходится постепенно снижать планку своих требований к качеству кода — и это приводит к росту количества «клякс».
Эти новые проблемные места (в дополнение к старым) тормозят нас всё больше и больше. Мы осознаём наличие проблем, но спешка в плане решения текущих задач не позволяет сфокусироваться на чём-либо ещё. Мы вынуждены работать больше, просто ради сохранения прежней скорости.
В какой-то момент вдруг оказывается, что половина кода, который мы пишем, предназначена для подпорок, обходов, хаков и преодоления других типов препятствий, созданных нами же ранее. Тут хороший код, там плохой, а здесь мы рыбу заворачивали.
Каждая прогулка по этому минному полю вместо прямой линии от точки А до точки Б вдруг становится запутанным маршрутом по лабиринту, без всякой гарантии достижения конечной цели. Даже сверх-усилия уже не позволяют вам двигаться к цели с той же скоростью, что и раньше.
Важность проблем теперь видна невооруженным глазом. И их нельзя исправить, просто выбросив всё и начав проект с нуля. Нам нужно выполнить много задач по рефакторингу кода, а на эти задачи нам нужно время, которое придётся просить у заказчика. Часто это время нам не будет выделено: мы ведь просим время для того, чтобы исправить собственный код, на разработку которого уже выделялось время ранее и о готовности которого мы же ранее сами и заявляли.
Даже если время и будет выделено, не стоит рассчитывать на быстрый результат. Мы сможем исправить лишь те проблемы, которые видим конкретно сейчас и лишь в том объёме, на который хватит выделенного времени (а его не будет много). Мы писали этот плохой код много недель (или месяцев), и у нас точно не будет столько же времени чтобы переписать этот код.
Это не тот путь, которым нам нужно идти. Длинные периоды рефакторинга не приносят большой и заметной сразу пользы проекту. Их очень трудно продать заказчику, поскольку он не увидит, за какую функциональность у него просят денег. То есть это плохая идея. Что же делать?
Упрощать! При получении каждой следующей задачи, мы намечаем план её реализации. Если по ходу этого плана мы упираемся в «кляксу» технического долга, то задача по его рефакторингу становится частью реализации текущей фичи. Конечно, мы не можем взяться сразу за все плохие места в коде. Но этого делать и не нужно! Если по ходу реализации какой-нибудь новой функциональности вы исправите больше старых «клякс», чем создадите новых подпорок и костылей — общее качество кода проекта повысится. В следующий раз, когда при работе над новой задаче вам вдруг придётся обратится к уже исправленному месту — вы с удовольствием отметите, что оно больше не требует полировки напильником, а сразу работает хорошо и выглядит приятно. Так и происходит разработка программного обеспечения.
Возможно, разработка каждой отдельной фичи таким образом займёт чуть-чуть больше времени, чем вы предполагали изначально. Но разработка всего набора функционала с таким подходом займёт меньше времени, поскольку на последних этапах перед дедлайном вы будете иметь возможность работать с относительно чистой кодовой базой, добавление нового функционала не будет отнимать время на поиски обходных путей. Кроме того, такой лично ваш подход к разработке хорошо скажется и на производительности всей команды.
Повторение — мать учения. С каждой новой фичей мы делаем код немного чище. Лишь чуть-чуть, но каждый раз. Много раз по «чуть-чуть» в какой-то момент позволят со спокойной душой написать новую, хорошо работающую фичу, за которую не стыдно, вместо того, чтобы рвать на себе волосы и бороться с желанием удалить вообще весь этот мусор.
Момент осознания полезности непрерывного рефакторинга не так далёк, как вам может показаться. Некоторые люди начинали замечать его уже к концу того же спринта, в котором они начали использовать данный подход. Силы непрерывности и инкрементальности процесса дают о себе знать очень быстро. С какого-то момента на выполнение новой задачи с рефакторингом начинает уходить МЕНЬШЕ времени, чем на выполнение этой же задачи без рефакторинга (в силу потраченного ранее времени на улучшения сопутствующего кода).
Работа идёт лучше, код становится чище и мы выдаём заказчику больше функционала, чем могли ранее. Все в выигрыше.
Так что рефакторинг — это не задача в Backlog, это часть каждой задачи в нём.
Комментарии (0)