Рефакторинг — это изменение внутренней структуры программного кода, которое упрощает его понимание и доработку без изменения внешнего поведения.
При рефакторинге программу не переписывают, не добавляют новых функций и не исправляют ошибки. Простыми словами, это «чистка» и упрощение кода, после которых программа работает так же, как раньше. Рефакторинг помогает вернуть коду качество, когда запутанная структура мешает доработкам.
Технический долг — это метафора, которую предложил Уорд Каннингем, для недостатков внутреннего качества кода, из-за которых его сложнее дорабатывать.
К таким недостаткам относятся:
- устаревшие фрагменты;
- запутанная структура модулей;
- плохо читаемый или трудный в поддержке код.
- Зачем нужен рефакторинг
- В каких случаях нужен рефакторинг
- Как делают рефакторинг на примерах
- Что не является рефакторингом
- Правила и методика рефакторинга
- Как встроить рефакторинг в процесс работы команды
- Сложности и ошибки рефакторинга
- Коротко о главном
Зачем нужен рефакторинг
Рефакторинг нужен, чтобы код оставался понятным, а доработки не дорожали со временем. Разработчику он упрощает работу, а заказчику ускоряет и удешевляет доработки. Идею проще увидеть на аналогии с укладкой кабеля в серверной, даже если вы не разработчик.

В одной части серверной кабели перепутаны, в другой уложены аккуратно. Хаос не означает, что запутанная часть не работает, содержит ошибки или ее нужно заменить новой. Чаще ей просто много лет, с ней работали специалисты разного уровня или никто не придерживался единых правил и структуры.
С кодом происходит то же самое. Пока запутанных участков мало, с ними легко работать: новый специалист быстро разбирается, а доработки и исправление ошибок занимают немного времени. Со временем проблем становится больше, и когда таких участков сотни или тысячи, от порядка в них зависит скорость всей разработки.

В рамках этой аналогии рефакторинг выглядит как поэтапное отключение и переподключение небольших секторов. Сектор отключают, содержимое перебирают и заново укладывают, затем проверяют работоспособность. В коде такая проверка — тестирование: если участок работает точно так же, как до изменений, правка прошла успешно. К следующему участку переходят, когда система снова работает и тесты проходят успешно (зеленые). По описанию Мартина Фаулера, автора сайта refactoring.com, рефакторинг состоит из серии небольших преобразований, после каждого из которых система остается рабочей, поэтому риск серьезной поломки ниже.

Конкретная польза от такой работы:
- доработки занимают меньше времени, потому что новую функцию не нужно встраивать в запутанный код;
- новому участнику команды проще понять код;
- ошибку проще найти, когда структура понятна;
- дублей меньше, поэтому одно изменение не приходится вносить в нескольких местах.
Что рефакторинг дает бизнесу и заказчику
Для оплачивающей стороны важна связь кода со сроками. Лишние усилия, которые уходят на каждую новую функцию в запутанном модуле, Фаулер сравнивает с процентами по долгу. Чем чаще приходится менять запутанный участок, тем больше таких процентов платит команда, а вместе с ней и заказчик.
По мнению Фаулера, смысл рефакторинга в том, чтобы с кодом было проще работать и команда быстрее добавляла ценность. Если не заниматься им по ходу работы, кодовая база постепенно деградирует, прогресс замедляется, а разговоры со спонсорами проекта усложняются. Для заказчика практический вывод такой: пока код остается понятным, новые требования к продукту реализуются быстрее.
В каких случаях нужен рефакторинг
Рефакторинг нужен, когда код мешает работе, и это видно как по самому коду, так и по работе команды. Признаки в коде:
- множество одинаковых фрагментов вместо вызова одной функции;
- слишком длинные или непонятные названия элементов программы;
- избыточное количество временных переменных;
- неиспользуемый или «мертвый» код;
- слишком длинные методы или классы;
- длинные списки параметров у методов и функций;
- «магические» числа, смысл которых непонятен из кода;
- огромное количество комментариев, многие из которых только усложняют понимание;
- заготовки на будущее, которые не довели до рабочего состояния или которые так и не понадобились;
- нагромождение из неиспользуемых библиотек.
Понять, что отделу разработки нужна чистка, можно и по косвенным признакам:
- Доработки занимают слишком много времени. Если каждая задача на добавление небольшой новой функции отнимает у программистов часы, дни, а иногда и месяцы, пора приводить код в порядок.
- Устранение ошибок требует долгого поиска проблемного участка. Если после сообщения об ошибке программисту приходится долго искать, где она возникла, пора рефакторить.
- Команда или подрядчики не могут разобраться в запутанном коде, «костыли» встречаются всюду, и без них не работают даже простые функции.
- Много дублирующихся фрагментов, и каждый из них приходится менять при доработке и исправлении ошибок.
- Код не соответствует стандартам разработки. У многих организаций есть собственные стандарты оформления кода, и если их нет или разработчики им не следуют, в программах появляется хаос. Пример — стандарты Google: руководства по стилю, которые компания применяет в собственном коде, в том числе для C++, Java, Python и Go.
Увидев несколько признаков из списков, не стоит переписывать код целиком. Достаточно найти участки, из-за которых команда теряет больше всего времени, и начать с них.
Как делают рефакторинг на примерах
Рефакторинг делают серией небольших правок, и каждая сохраняет поведение программы. Три простых приема ниже показывают, что именно в коде меняется.
Замена сложных операторов на методы
Задача: есть фрагмент кода, где используется сложный оператор (if-then/else или switch).
Решение: все сложные части оператора нужно выделить в отдельные методы. Тогда условие читается как короткая фраза, а подробности спрятаны в методах с понятными названиями.

Переименование непонятного метода
Задача: есть метод getsmn(), название которого не объясняет, что он делает.
Решение: переименовать метод так, чтобы из названия было понятно, что он делает. Новое название — getSecondName(). Хорошее имя отвечает на вопрос «что делает метод», поэтому читать код становится проще, а поведение остается прежним. В вызове меняется только имя:
// до
name = user.getsmn();
// после
name = user.getSecondName();
Группировка фрагментов программы
Задача: в методе есть блок строк, который выполняет отдельную подзадачу и может быть сгруппирован.
Решение: вынести этот блок в новый метод или функцию и вызвать ее вместо старого фрагмента. Длинный метод превращается в набор коротких шагов с понятными названиями.

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


Комментарии (2)
Оставить комментарий