Рефакторинг — изменение внутренней структуры кода без изменения его внешнего поведения. Определение простое, а вот отношение к нему в командах разное: одни считают его непозволительной роскошью, другие превращают в бесконечную переделку ради красоты. Мы поддерживаем и развиваем чужие проекты, и у нас на этот счёт прикладной взгляд: рефакторинг оправдан тогда, когда он снижает стоимость будущих изменений. Ниже — как мы это оцениваем, в каком порядке действуем и чего стараемся не делать.
Что рефакторинг решает, а что нет
Смысл процедуры в том, что стоимость правки в коде растёт вместе с его запутанностью. Сначала небольшая доработка занимает пару часов, через год похожая задача — неделю, потому что нужно разобраться, где ещё используется этот кусок, и проверить пять сценариев вручную. Рефакторинг возвращает стоимость изменений к разумному уровню.
Термин, который здесь уместен, — технический долг. Это накопленные компромиссы: временное решение, оставленное надолго, дублирование вместо общей функции, обход вместо исправления причины. Долг сам по себе не порок, ошибкой становится его невозвратность: пока проценты по нему растут, каждая новая задача обходится дороже предыдущей.
Чего рефакторинг не делает. Он не добавляет функций, поэтому его результат не виден пользователю напрямую. Он не исправляет ошибки в бизнес-логике — если правило посчитано неверно, после перестановки методов оно останется неверным. И он не заменяет проектирование: аккуратно оформленная неудачная архитектура остаётся неудачной.
Признаки, по которым мы понимаем, что пора
Мы не запускаем рефакторинг «потому что код старый». Есть наблюдаемые сигналы.
- Простая по смыслу задача требует правок в нескольких далёких друг от друга местах.
- После каждой доработки в другом месте ломается что-то не связанное.
- Разработчик боится трогать файл и предпочитает написать рядом вторую версию функции.
- Один и тот же расчёт живёт в трёх экземплярах, и они уже разошлись.
- Новому человеку требуется несколько дней, чтобы внести первое изменение.
- Оценка задачи стабильно выше, чем кажется по её описанию, и команда не может объяснить разницу иначе как «там сложно».
Если ни один сигнал не проявляется, а код просто написан не в том стиле, который нравится текущей команде, — это не повод для работ.
Запахи кода и что мы с ними делаем
Запах кода (code smell) — не ошибка, а признак того, что структура, вероятно, требует внимания. Опираться на такие признаки удобно: они конкретны и их видно при чтении.
| Признак | Как проявляется в проекте | Обычное направление правки |
|---|---|---|
| Дублирование | Одинаковый расчёт скидки в корзине, в письме и в админке | Вынести в одну функцию, оставить единственный источник правила |
| Длинный метод | Функция на несколько сотен строк с несколькими уровнями вложенности | Выделить осмысленные шаги в отдельные функции с говорящими именами |
| Большой класс | Объект отвечает и за данные, и за отправку почты, и за формирование HTML | Разделить обязанности, оставить одну зону ответственности |
| Длинный список параметров | Вызов функции с восемью аргументами, половина из которых пустые | Собрать связанные параметры в объект или структуру |
| Магические значения | Числа и строки статусов прямо в условиях, без пояснений | Вынести в именованные константы или перечисление |
| Разросшееся условие | Цепочка ветвлений на десятки вариантов в одном месте | Таблица соответствий или отдельные обработчики |
| Мёртвый код | Функции и файлы, на которые нет ни одной ссылки | Удалить, полагаясь на историю изменений как на архив |
| Комментарий вместо имени | Пояснение, что делает переменная a2 или метод doIt | Переименовать так, чтобы комментарий стал лишним |
Список не исчерпывающий и не является планом работ. Он нужен, чтобы при разборе кода говорить предметно: не «здесь плохо», а «здесь три копии одного правила, и две из них устарели».
Порядок работы, который мы соблюдаем
- Зафиксировать текущее поведение. Прежде чем менять структуру, нужно уметь проверить, что поведение не изменилось. Если тестов нет, мы пишем их именно на тот участок, который собираемся трогать. Это называют характеризующими тестами: они закрепляют то, как система работает сейчас, даже если это работа не идеальна.
- Ограничить область. Один заход — один участок: класс, модуль, набор связанных функций. Попытка привести в порядок всё сразу заканчивается веткой, которую невозможно ни проверить, ни влить.
- Двигаться мелкими шагами. Переименование, выделение метода, перенос функции — каждый шаг небольшой и обратимый, после каждого запускаются тесты.
- Разделять правки по смыслу. Изменение структуры и изменение поведения не попадают в один коммит. Иначе при разборе ошибки невозможно понять, что именно её вызвало.
- Проверять на реальных данных. Копия боевой базы показывает то, чего не покажет тестовый набор из десяти записей: пустые поля, старые форматы, записи, созданные предыдущей версией системы.
- Выкладывать частями. Небольшие изменения, доезжающие до продакшена регулярно, безопаснее, чем один большой выпуск после месяца работы.
Отдельно про инструменты. Автоматические преобразования в средах разработки — переименование, выделение метода, перемещение — надёжнее ручной правки, потому что учитывают все места использования. Статический анализ показывает неиспользуемый код и подозрительные конструкции. Но ни то, ни другое не заменяет тесты: инструмент гарантирует корректность преобразования, а не корректность результата.
Как встроить рефакторинг в график работ
Главный организационный вопрос — за чей счёт. Отдельный проект «наведём порядок в коде» бизнесу продать трудно: результат не виден снаружи. Работающие варианты такие.
- Правило соседства. Приводим в порядок тот участок, который и так открываем по задаче. Правка растёт в объёме незначительно, а код улучшается там, где его действительно трогают.
- Доля от объёма. Заранее согласованная часть времени в каждом цикле работ уходит на технический долг. Это делает расходы предсказуемыми.
- Подготовка к задаче. Если крупная доработка упирается в запутанный участок, рефакторинг включается в неё отдельным этапом с понятным обоснованием: без него сама доработка будет дороже.
- Реестр долга. Проблемные места фиксируются списком с оценкой, чего они стоят. Тогда разговор с заказчиком ведётся не в терминах «код плохой», а в терминах сроков и рисков.
Ошибки, которые обходятся дороже самого беспорядка
- Переписывание с нуля вместо постепенного улучшения. Новая версия догоняет старую дольше, чем ожидается, а старая всё это время требует поддержки. Ещё и бизнес-правила, зашитые в старом коде, при таком подходе теряются первыми.
- Рефакторинг без тестов. Тогда это не рефакторинг, а изменение кода с надеждой, что поведение сохранилось.
- Смешивание с новой функциональностью. Разбор причин последующих ошибок превращается в гадание.
- Массовое переформатирование заодно. История изменений заполняется правками, в которых не найти смысловых.
- Улучшение того, что не трогают. Время уходит на участок, который годами работает и не меняется, а узкое место остаётся на месте.
- Бесконечная полировка. У работ должен быть критерий завершения, иначе они не заканчиваются никогда.
Что считать результатом
Чтобы разговор о пользе не сводился к ощущениям, мы фиксируем измеримое: сколько времени занимает типовая правка в этом модуле, сколько мест приходится менять ради одного изменения, сколько ошибок возвращается после выкладки, сколько времени идёт сборка и прогон тестов. Эти числа снимаются до работ и после, и по ним видно, окупился ли заход.
Ещё один практичный признак: снизился ли страх перед файлом. Если разработчик перестал обходить участок стороной и правит его напрямую, цель достигнута, даже если снаружи ничего не изменилось.
Коротко
Рефакторинг — не разовая уборка, а часть нормального обслуживания системы. Он делается небольшими порциями, под защитой тестов, на тех участках, которые действительно мешают развитию, и с понятным критерием окончания. В таком виде он экономит деньги, а не тратит их.
Если код проекта стал дорог в обслуживании и каждая доработка занимает больше времени, чем должна, обратитесь за услугой техническая поддержка и развитие сайта. Мы разбираем состояние кода, показываем проблемные участки с оценкой и приводим их в порядок постепенно, не останавливая работу проекта.











