Основы программирования
Рефакторинг: улучшение кода без изменения поведения
Код читается в 10 раз чаще, чем пишется. Если через 6 месяцев ты не понимаешь свой код - это провал. Рефакторинг - это уважение к своему будущему «я» и к коллегам.
- Google: любой код проходит code review - читаемость критична
- Legacy-системы: без рефакторинга банковский код 1990-х становится нечитаемым за 30 лет
- Open Source: понятный код получает больше контрибьюторов
- Техдолг: каждый «быстрый фикс» без рефакторинга делает следующее изменение дороже
Предварительные знания
- Уметь читать чужой код: разобрать функцию, понять зависимости между файлами
- Базовое понимание ООП и SOLID: для рефакторинга больших классов
- Опыт работы с системой контроля версий (git): рефакторинг идёт малыми коммитами
От диссертации Опдайка до IntelliJ и второго издания Фаулера
Слово refactoring как технический термин впервые появилось в диссертации Уильяма Опдайка Refactoring Object-Oriented Frameworks, Университет Иллинойса, 1992 год. Опдайк работал под руководством Ральфа Джонсона (одного из четверых GoF) и описал автоматизированные преобразования над Smalltalk-кодом, сохраняющие поведение. В 1995 Джон Робертс и Дон Брант на той же кафедре собрали Smalltalk Refactoring Browser, первый IDE-инструмент, который умел выполнять Extract Method, Rename, Move Method одним нажатием. В 1999 Мартин Фаулер выпустил книгу Refactoring: Improving the Design of Existing Code: 70+ каталогизированных рефакторингов на Java с пошаговыми инструкциями и code smells. В том же году Кент Бек выпустил Extreme Programming Explained, где рефакторинг стал одной из 12 практик XP вместе с TDD и парным программированием. В 2001 Максим Моссиенко в команде JetBrains добавил в IntelliJ IDEA первое в Java-мире меню Refactor с десятками автоматизированных операций; через несколько лет это меню скопировали Eclipse, NetBeans и Visual Studio. В 2018 Фаулер выпустил второе издание Refactoring, переписав все примеры с Java на JavaScript: язык изменился, но каталог за 20 лет почти не устарел.
Extract Function: разбивай длинные функции
**Самый частый рефакторинг:** если функция стала слишком длинной или её часть имеет смысл как самостоятельная операция - выделяй в новую функцию. Правило: функция должна делать одно дело и делать это хорошо.
Когда функцию нужно разбить на несколько?
Переименование: код должен читаться как текст
**Плохие имена - корень всех зол.** Переименование - простейший, но самый высокорычажный рефакторинг. Хорошее имя снимает потребность в комментарии.
Какое имя лучше для переменной, хранящей флаг «пользователь авторизован»?
Replace Conditional with Polymorphism
Длинные цепочки if/elif/else по одному полю - признак того, что нужен полиморфизм или словарь диспатч. Паттерн «стратегия» делает код расширяемым.
Длинная цепочка if/elif - это плохой стиль. Её надо немедленно заменить полиморфизмом или Strategy, потому что так предписывает Фаулер.
Replace Conditional with Polymorphism оправдан, когда веток 3+ И они меняются вместе И различаются поведением, а не данными. Для 2 веток или для switch по enum-у класс-иерархия добавляет больше сложности, чем убирает.
Рефакторинг как ритуал («увидел if - замени») путает форму с целью. Фаулер сам подчёркивает: рефакторинг применяется по запаху, а не по шаблону. Полиморфизм оправдан, когда добавление нового case без полиморфизма требует менять N мест - тогда классы дают расширяемость. На 2 ветках или однократном switch иерархия классов утяжеляет понимание, а не упрощает.
Какой «запах кода» (code smell) указывает на необходимость паттерна Стратегия?
Ключевые идеи
- Extract Function: одна функция = одна ответственность
- Переименование: лучшее имя = лучший комментарий
- Replace Conditional with Polymorphism: убирает if-switch цепочки
- Рефакторинг НЕ меняет поведение - сначала тест, потом рефактор
- «Сначала сделай зелёными тесты, потом рефакторинг»
Связанные темы
Рефакторинг невозможен без тестов:
- Паттерны проектирования — Рефакторинг часто ведёт к паттернам
- Тестирование — Тесты - защитная сетка при рефакторинге
Вопросы для размышления
- Почему рефакторинг нужно делать малыми шагами? Что происходит при «мегарефакторинге» одним коммитом?
- Как отличить рефакторинг от реструктуризации (изменения логики)?
- Найдите в своём коде одну функцию, которую можно улучшить через Extract Function.
Связанные уроки
- prog-13-patterns — Рефакторинг часто ведёт к паттернам как более чистому решению
- prog-15-testing — Без тестов рефакторинг опасен: тесты страхуют изменения
- plt-01-paradigms — Paradigm shift - крайний случай рефакторинга
- db-11-query-optimization — Query optimization - рефакторинг SQL: то же поведение, чище план
- alg-01-big-o