«Не трогай, оно работает». Эту фразу слышал каждый разработчик, глядя на код, написанный пять лет назад уволившимся коллегой. Legacy-код — это не просто старый код. По определению Майкла Фезерса, автора книги «Working Effectively with Legacy Code», это код без тестов. И неважно, написан он вчера или в 2010-м: если нет автоматизированных тестов — это legacy. По статистике, компании тратят 50% времени рефакторинга только на то, чтобы понять, как работает существующий код. Почти треть всех IT-проектов отменяется, а более 80% считаются провальными — и значительная часть этих проблем связана с техническим долгом. В этой статье разберёмся, как безопасно рефакторить легаси, какие техники и паттерны использовать, как измерять технический долг и — самое сложное — как убедить менеджмент и команду, что рефакторинг нужен.
1. Что такое легаси-код и почему он появляется
Определения легаси-кода
| Определение | Источник | Суть |
|---|---|---|
Код без тестов | Майкл Фезерс | Если нет автоматизированных тестов — это legacy, даже если написано вчера |
Код, который страшно менять | Практическое | Разработчики боятся что-то сломать, поэтому не трогают |
Код, автор которого недоступен | Организационное | Никто не знает, почему так написано и как это работает |
Устаревший технологический стек | Техническое | Старые фреймворки, языки, библиотеки без поддержки |
Почему легаси накапливается
| Причина | Описание | Последствие |
|---|---|---|
Давление дедлайнов | «Сделай быстро, потом поправим» | «Потом» никогда не наступает |
Текучка кадров | Автор кода ушёл, документации нет | Знания потеряны |
Эволюция требований | Продукт менялся, архитектура — нет | Костыли поверх костылей |
Отсутствие культуры тестирования | Тесты не писались изначально | Страх любых изменений |
«Работает — не трогай» | Менталитет избегания риска | Код деградирует со временем |
Недооценка техдолга | Бизнес не видит проблемы | Долг накапливается экспоненциально |
Симптомы легаси-проекта
Разработка новых фич занимает всё больше времени
Количество багов растёт, а не снижается
Onboarding новых разработчиков — месяцы, а не недели
Никто не понимает, как работают целые модули
Страх перед любыми изменениями в «тех» местах
Регулярные «пожары» на продакшене
Определение Фезерса: «У меня нет проблем с определением легаси-кода как кода без тестов. Это рабочее определение, и оно указывает на решение.»
2. Психология страха: почему разработчики боятся рефакторить
Корни страха
Страх перед рефакторингом — это не слабость, а рациональная реакция на неопределённость. Когда разработчик не знает, что делает код и как изменения повлияют на систему, естественная реакция — не трогать.
| Источник страха | Проявление | Последствие |
|---|---|---|
Отсутствие тестов | Нет автоматической проверки поведения | «Сломаю — никто не заметит до продакшена» |
Непонимание кода | Не ясно, зачем этот код существует | «Может, он там нужен?» |
Культура наказания за ошибки | Баги = негативная оценка | Минимизация риска любой ценой |
Давление дедлайнов | «Некогда рефакторить, надо фичи» | Рефакторинг откладывается навечно |
Синдром самозванца | «Может, я просто не понимаю?» | Джуниоры следуют плохим паттернам |
Цитата: «TDD — это способ управления страхом во время программирования. Страх делает вас неуверенными. Страх заставляет вас меньше коммуницировать. Страх отталкивает вас от обратной связи. Страх делает вас раздражительными.»
Порочный круг страха
Цикл деградации кода:
Нет тестов → Страх менять код → Обходные решения вместо рефакторинга → Код становится сложнее → Ещё страшнее менять → Ещё меньше тестов... → Легаси
Как преодолеть страх
| Проблема | Решение |
|---|---|
| Нет тестов | Написать characterization tests перед изменениями |
| Не понимаю код | Потратить время на исследование перед рефакторингом |
| Боюсь ошибиться | Маленькие шаги + частые коммиты + feature flags |
| Нет поддержки команды | Pair programming с senior-разработчиком |
| Культура наказания | Менять культуру: ошибки — это обучение |
Принцип: «Fearless refactoring» — концепция из agile, согласно которой разработчик должен уметь инкрементально менять код, не боясь его сломать. Это достигается через тесты и практику.
3. Книга Фезерса: ключевые концепции
О книге
«Working Effectively with Legacy Code» Майкла Фезерса — библия работы с легаси. Книга предлагает 24 техники разрыва зависимостей и концепцию «швов» (seams) для безопасного изменения кода.
Концепция Seam (Шов)
Шов — это место в коде, где можно изменить поведение без редактирования самого кода. Это точка входа для тестирования там, где тестов раньше не было.
Определение Seam:
«Шов — это точка, в которой можно влиять на поведение программы без изменения кода в этом месте.»
Типы швов
| Тип шва | Описание | Пример |
|---|---|---|
Object Seam | Замена объекта через полиморфизм | Передать mock вместо реального сервиса |
Preprocessing Seam | Изменение на этапе препроцессинга | #ifdef в C/C++ |
Link Seam | Замена на этапе линковки | Подмена библиотеки |
Техники Sprouting и Wrapping
| Техника | Когда использовать | Как работает |
|---|---|---|
Sprout Method | Нужно добавить новую функциональность | Создать новый метод с тестами, вызвать из старого кода |
Sprout Class | Новая функциональность слишком сложна | Создать отдельный класс с тестами |
Wrap Method | Нужно добавить поведение до/после существующего | Обернуть старый метод новым |
Wrap Class | Нужно изменить поведение класса | Декоратор или адаптер |
24 техники разрыва зависимостей
Книга содержит каталог из 24 техник для изоляции кода и написания тестов. Некоторые ключевые:
Extract Interface: Выделить интерфейс для замены зависимости моком
Parameterize Constructor: Передавать зависимости через конструктор
Subclass and Override Method: Унаследовать и переопределить проблемный метод
Extract and Override Call: Вынести вызов в отдельный метод для переопределения
Introduce Instance Delegator: Создать экземплярный метод вместо статического
4. Characterization Tests: тесты на существующее поведение
Что такое Characterization Tests
Characterization test (тест характеризации) — это тест, который описывает фактическое поведение кода, а не ожидаемое. Вместо того чтобы писать тесты «как должно быть», вы фиксируете «как есть сейчас».
Определение: «Characterization test — это тест, который характеризует реальное поведение участка кода. Вместо комплексных unit-тестов вы захватываете текущее поведение. Делаете снимок того, что код делает. Тест гарантирует, что это поведение не изменится.»
Зачем нужны
| Цель | Описание |
|---|---|
Safety net для рефакторинга | Тест сообщит, если поведение изменилось |
Быстрое покрытие | Не нужно понимать код, чтобы написать тест |
Документация поведения | Тесты показывают, что код реально делает |
Обнаружение багов | Иногда «баг» оказывается ожидаемым поведением |
Как писать Characterization Tests
Вызвать код с определённым input
Посмотреть output (можно через debugger или print)
Записать assertion с этим output
Повторить для разных inputs и edge cases
// Пример characterization test (Python)
def test_calculate_discount_characterization():
# Мы не знаем, как должно работать
# Но мы зафиксируем, как работает сейчас
result = calculate_discount(100, "SUMMER2024")
# Оказалось, скидка 15%. Фиксируем.
assert result == 85
result2 = calculate_discount(100, "INVALID")
# Невалидный код не даёт скидку
assert result2 == 100
result3 = calculate_discount(0, "SUMMER2024")
# Edge case: цена 0
assert result3 == 0
Альтернативные названия
Эту технику также называют:
Golden Master Testing
Approval Testing
Snapshot Testing
Locking Tests
Regression Tests
5. Golden Master: снимок поведения системы
Как работает Golden Master
Golden Master — техника от Майкла Фезерса для тестирования кода, который вы не понимаете. Идея: сгенерировать множество входных данных, записать выходные данные, и использовать их как эталон для сравнения после изменений.
Алгоритм Golden Master:
1. Создать N случайных входов (с фиксированным seed для воспроизводимости)
2. Прогнать через тестируемый код
3. Записать все выходы в файл (Golden Master)
4. После изменений: прогнать снова и сравнить с записанным
5. Если совпадает — рефакторинг безопасен. Если нет — что-то сломалось.
Преимущества
✅ Высокое покрытие очень быстро
✅ Не нужно понимать код
✅ Работает для сложных систем с множеством состояний
✅ Инструменты автоматизируют процесс
Инструменты для Approval Testing
| Инструмент | Языки | Особенности |
|---|---|---|
ApprovalTests | Java, C#, Ruby, Python | Популярный, много интеграций |
Jest Snapshots | JavaScript | Встроено в Jest |
Verify | .NET | Современная альтернатива ApprovalTests |
syrupy | Python | Для pytest |
Когда использовать
Рефакторинг сложного легаси без тестов
Миграция на новую версию библиотеки
Оптимизация алгоритмов (проверка, что результат не изменился)
Рекомендация: «Начните с Golden Master для кода без тестов, затем используйте TDD для написания нормальных unit-тестов по мере рефакторинга. Когда закончите — решите, оставлять ли approval tests.»
6. Паттерн Strangler Fig: постепенная миграция
Что такое Strangler Fig
Strangler Fig (Душитель Фига) — паттерн миграции легаси-системы, предложенный Мартином Фаулером. Название вдохновлено тропическим растением, которое обвивает дерево-хозяина и постепенно его замещает.
Аналогия: Как фикус-душитель постепенно обвивает и замещает дерево-хозяина, новая система постепенно замещает легаси, пока старую можно полностью удалить.
Как работает
Фазы Strangler Fig:
1. Transform: Создаём новый компонент рядом со старым
2. Coexist: Оба работают параллельно, фасад перенаправляет трафик
3. Eliminate: Когда всё перенесено — удаляем старый компонент
Архитектура
| Компонент | Роль |
|---|---|
Façade (Proxy) | Перехватывает запросы и направляет к старой или новой системе |
Legacy System | Старая система, которую заменяем |
New Components | Новые микросервисы/модули, замещающие функциональность |
Anti-Corruption Layer | Защита новых компонентов от «грязи» легаси |
Преимущества
✅ Минимальный риск — изменения инкрементальные
✅ Пользователи не замечают миграции
✅ Можно откатить на любом этапе
✅ Ценность доставляется постепенно
✅ Новые фичи можно сразу делать в новой системе
Ограничения
| Ограничение | Описание |
|---|---|
Нужен доступ к коду | Без доступа к исходникам легаси сложно интегрировать |
Façade = SPOF | Прокси может стать точкой отказа |
Shared resources | БД и другие ресурсы могут использоваться обеими системами |
Древние технологии | Если легаси на COBOL — интеграция будет сложной |
Когда использовать
Миграция монолита на микросервисы
Переход на новый стек (Python → Go, Ruby → Rust)
Замена устаревшего модуля
Когда Big Bang rewrite — слишком рискованно
7. Инкрементальный рефакторинг: маленькие шаги
Почему Big Bang — плохая идея
🚫 Анти-паттерн: Big Bang Refactoring
Переписать всё с нуля за один раз — почти всегда ошибка. Причины:
• Новая система накапливает свои баги
• Бизнес не получает ценности месяцами
• Требования меняются за время переписывания
• Часто проект отменяется, не дойдя до конца
• Потеря неявных знаний, закодированных в легаси
Принцип Baby Steps
Идея: проводить как можно меньше времени в «сломанном» состоянии. Вместо одного большого изменения — серия микро-изменений, каждое из которых сохраняет рабочее состояние.
Пример Baby Steps: переименование переменной
| Шаг | Действие | Состояние |
|---|---|---|
| 1 | Создать новую переменную с хорошим именем | ✅ Работает |
| 2 | Скопировать значение старой переменной | ✅ Работает |
| 3 | Заменить одно использование старой → новой | ✅ Работает |
| 4 | Повторить для всех использований | ✅ Работает |
| 5 | Удалить старую переменную | ✅ Работает |
Правила инкрементального рефакторинга
Одно изменение за раз: Не смешивайте рефакторинг с добавлением функциональности
Частые коммиты: Каждый маленький шаг — коммит. Легко откатить
Тесты зелёные: Рефакторить только когда тесты проходят
Continuous Integration: Интегрировать изменения в основную ветку регулярно
Feature Flags: Новый код можно включать/выключать без редеплоя
8. Boy Scout Rule: оставляй код чище, чем нашёл
Суть правила
Boy Scout Rule (Правило Бойскаута) — принцип, сформулированный Робертом Мартином (Uncle Bob): «Всегда оставляй код чище, чем он был до тебя».
Аналогия: «Всегда оставляй поляну чище, чем нашёл». Если видишь мусор — убери, даже если не ты его оставил.
Как применять
| Ситуация | Действие по Boy Scout Rule |
|---|---|
| Фиксишь баг | Переименуй непонятную переменную рядом |
| Добавляешь фичу | Выдели метод, если функция слишком длинная |
| Code review | Предложи мелкие улучшения |
| Читаешь код | Добавь комментарий, если разобрался в сложном месте |
Micro Refactoring
Micro refactoring — применение Boy Scout Rule через маленькие, целенаправленные изменения:
Переименовать переменную
Удалить неиспользуемый код
Упростить условие
Выделить константу
Добавить или улучшить комментарий
Баланс: не уходи в rabbit hole
⚠️ Опасность: Можно начать с одного улучшения, потом увидеть другое, и ещё одно... и потратить день на рефакторинг вместо основной задачи.
Решение: Установите лимит времени. 15 минут — максимум на «попутные» улучшения. Если нужно больше — создайте тикет.
Принцип: «Вам не нужно делать каждый модуль идеальным перед коммитом. Достаточно сделать его немного лучше, чем было. И любой код, который вы добавляете — должен быть чистым.»
9. Code Smells: запахи кода и как их устранять
Что такое Code Smells
Code smell (запах кода) — это признак потенциальной проблемы в коде. Это не баг: код работает. Но запах указывает на нарушение принципов дизайна, которое усложнит поддержку.
Категории запахов
| Категория | Примеры | Проблема |
|---|---|---|
Bloaters | Long Method, Large Class, Primitive Obsession | Код разросся до неуправляемых размеров |
Object-Orientation Abusers | Switch Statements, Parallel Inheritance | Неправильное использование ООП |
Change Preventers | Divergent Change, Shotgun Surgery | Изменение требует правок в многих местах |
Dispensables | Dead Code, Duplicate Code, Comments | Лишний код, который только мешает |
Couplers | Feature Envy, Inappropriate Intimacy | Чрезмерная связанность классов |
Топ-10 запахов и рефакторинги
| Запах | Описание | Рефакторинг |
|---|---|---|
Long Method | Метод слишком длинный | Extract Method |
Large Class | Класс делает слишком много | Extract Class, Extract Interface |
Duplicate Code | Одинаковый код в разных местах | Extract Method, Pull Up Method |
Dead Code | Неиспользуемый код | Safe Delete |
Long Parameter List | Слишком много параметров | Introduce Parameter Object |
Feature Envy | Метод больше использует чужой класс | Move Method |
God Class | Один класс контролирует всё | Extract Class, Decompose |
Primitive Obsession | Использование примитивов вместо объектов | Replace Primitive with Object |
Magic Numbers | Непонятные числа в коде | Extract Constant |
Comments | Комментарии объясняют плохой код | Extract Method, Rename |
Базовые техники рефакторинга
Extract Method
Выделение части кода в отдельный метод с понятным именем:
# До
def process_order(order):
# validate
if not order.items:
raise ValueError("Empty order")
if order.total < 0:
raise ValueError("Invalid total")
# calculate discount
discount = 0
if order.total > 100:
discount = order.total * 0.1
# ... ещё 50 строк
# После
def process_order(order):
validate_order(order)
discount = calculate_discount(order)
# ... остальная логика
def validate_order(order):
if not order.items:
raise ValueError("Empty order")
if order.total < 0:
raise ValueError("Invalid total")
def calculate_discount(order):
if order.total > 100:
return order.total * 0.1
return 0
Rename Method/Variable
Одна из самых эффективных и безопасных техник. Хорошее имя — лучшая документация:
# До
def proc(d, t):
return d * (1 + t/100)
# После
def calculate_price_with_tax(base_price, tax_rate_percent):
return base_price * (1 + tax_rate_percent/100)
10. Метрики технического долга
Зачем измерять
Чтобы убедить менеджмент в необходимости рефакторинга, нужны числа. «Код плохой» — не аргумент. «Время на добавление фичи выросло на 40% за год» — аргумент.
Ключевые метрики
| Метрика | Что измеряет | Как интерпретировать |
|---|---|---|
Technical Debt Ratio (TDR) | Стоимость исправления / размер кодовой базы | Чем выше — тем хуже качество |
Cyclomatic Complexity | Количество путей выполнения | > 10 — сложно тестировать, > 20 — рефакторить |
Cognitive Complexity | Когнитивная нагрузка на разработчика | Чем выше — тем сложнее понять код |
Code Churn | Частота изменений файла | Высокий churn + низкое качество = проблема |
Defect Density | Баги / размер модуля | Указывает на проблемные области |
Test Coverage | % кода под тестами | Низкое покрытие = высокий риск |
Cycle Time | Время от коммита до продакшена | Рост указывает на накопление долга |
Три главные метрики (по исследованиям)
Ownership: Сколько разработчиков меняют модуль
→ Мало контрибьюторов = лучше качество
→ Много контрибьюторов = накопление долга
Cohesion: Насколько элементы модуля связаны
→ Высокая когезия = модуль делает одну вещь
→ Низкая когезия = разношёрстный код
Churn: Как часто код меняется
→ Высокий churn + низкое качество = приоритет рефакторинга
Инструменты измерения
| Инструмент | Что делает | Языки |
|---|---|---|
SonarQube | Комплексный анализ: долг, баги, уязвимости | 25+ языков |
CodeScene | Анализ поведения команды + CodeHealth | Любые |
NDepend | Глубокий анализ для .NET | .NET |
Code Climate | CI-интеграция, maintainability score | Популярные языки |
Codacy | Автоматический code review | 30+ языков |
11. Как убедить менеджмент
Почему это сложно
Менеджеры мыслят в терминах бизнес-ценности, сроков и денег. «Нам нужен рефакторинг» для них звучит как «хотим потратить время на что-то, что не добавит фич». Ваша задача — перевести на их язык.
Аналогия кредитной карты
Скрипт: «Вы комфортно себя чувствуете, когда не платите по кредитной карте месяцами? Технический долг — как кредит. Чем дольше не платим — тем больше проценты. Сейчас каждая фича занимает на 30% больше времени, чем год назад. Это и есть "проценты".»
Стратегии убеждения
| Стратегия | Как применить | Пример |
|---|---|---|
Говорите на языке бизнеса | Переводите технические проблемы в деньги/время | «Это сократит время разработки фич на 20%» |
Покажите данные | Метрики velocity, bug rate, cycle time | «Velocity упала с 40 до 25 points за год» |
ROI конкретных улучшений | Оценка выигрыша от конкретного рефакторинга | «1 час рефакторинга сэкономит 9 минут на каждый деплой» |
Удержание сотрудников | Связь качества кода с моралью команды | «Разработчики уходят из-за legacy» |
Риски безопасности | Устаревшие зависимости = уязвимости | «Библиотека не поддерживается, CVE опубликованы» |
Что отслеживать для презентации
Velocity тренд: Снижается ли скорость команды?
Bug rate: Количество багов в неделю растёт?
Time to fix: Сколько времени уходит на исправление?
Lead time: От идеи до продакшена — сколько?
Developer satisfaction: Что говорят на ретро?
Подход «включи в estimate»
Совет от менеджера: «Включай рефакторинг во все свои оценки. Это не проблема, о которой менеджмент хочет думать. Ты инженер — ты её решаешь. Просто делай это незаметной частью каждой задачи.»
Модель 20% capacity
Предложите устойчивую модель: 20% каждого спринта — на технический долг. Это не останавливает разработку фич, но обеспечивает постоянный прогресс.
12. Как убедить команду
Сопротивление изменениям
Не только менеджмент сопротивляется рефакторингу. Команда тоже может быть против:
| Возражение | Реальная причина | Как преодолеть |
|---|---|---|
| «Нет времени» | Рефакторинг не приоритизирован | Включить в Definition of Done |
| «Работает — не трогай» | Страх сломать | Покрыть тестами, pair programming |
| «Я не автор этого кода» | Нет ownership | Collective code ownership |
| «Это не моя проблема» | Силосы в команде | Mob programming, ротация |
| «Мы уже пробовали» | Прошлый негативный опыт | Начать с маленьких побед |
Культурные изменения
Boy Scout Rule в Definition of Done: «Код чище, чем был»
Рефакторинг = нормальная часть работы, не «extra»
Pair programming для передачи знаний
Mob programming для сложных рефакторингов
Безопасность ошибок: Сломал при рефакторинге? Это обучение, не наказание
Начните с маленьких побед
Найдите очевидно плохой кусок кода, который все ненавидят
Покройте тестами
Отрефакторьте
Покажите результат: «Было 300 строк, стало 80»
Расскажите, как это упростило добавление фичи
13. Приоритизация рефакторинга
Что рефакторить в первую очередь
Не нужно рефакторить всё. Фокусируйтесь на местах с максимальным ROI.
Матрица приоритизации
| Часто меняется | Редко меняется | |
|---|---|---|
Высокая сложность | 🔴 Приоритет №1 | 🟡 Средний приоритет |
Низкая сложность | 🟡 Средний приоритет | 🟢 Низкий приоритет |
Критерии приоритизации
| Критерий | Высокий приоритет если |
|---|---|
Business-critical | Сбой вызовет серьёзные последствия |
High churn | Код часто меняется |
Bug hotspot | Много багов в этом модуле |
Bottleneck | Замедляет разработку других фич |
Knowledge silo | Только один человек понимает код |
Security risk | Устаревшие зависимости с уязвимостями |
Категоризация техдолга
No-brainer: Критичные задачи, без которых продукт не работает → Делать немедленно
Worthy investment: Улучшит maintainability, снизит риски → Планировать
Quick wins: Маленькие улучшения, можно дать новичкам → При возможности
Not worth it: Решится само или не критично → Игнорировать
14. Анти-паттерны легаси-кода
Распространённые анти-паттерны
| Анти-паттерн | Описание | Последствия |
|---|---|---|
Spaghetti Code | Код без структуры, всё переплетено | Невозможно понять и изменить |
God Class | Один класс делает всё | Изменение ломает всё |
Lava Flow | Мёртвый код, который никто не удаляет | Путаница, ложные зависимости |
Big Ball of Mud | Система без архитектуры | Каждое изменение — риск |
Copy-Paste Programming | Дублирование вместо переиспользования | Баг фиксится в одном месте, остаётся в других |
Golden Hammer | Одно решение для всех проблем | Неоптимальные решения |
Cargo Cult | Копирование без понимания | Код, который работает «магически» |
Статистика провалов
Статистика IT-проектов:
• Почти 1/3 всех проектов отменяется
• 2/3 проектов превышают бюджет на 200%+
• Более 80% проектов считаются провальными
Значительная часть связана с накопленным техническим долгом.
15. Инструменты и автоматизация
IDE рефакторинг
Современные IDE предоставляют автоматизированные рефакторинги, которые безопаснее ручных:
| IDE | Ключевые возможности |
|---|---|
JetBrains (IntelliJ, PyCharm, WebStorm) | Rename, Extract, Inline, Move, Change Signature |
VS Code | Базовые рефакторинги + extensions |
Visual Studio | Полный набор для C#/.NET |
Статический анализ
| Инструмент | Назначение |
|---|---|
SonarQube | Комплексный анализ качества |
ESLint/Prettier | JavaScript: стиль + потенциальные ошибки |
Pylint/Ruff | Python: стиль + ошибки |
RuboCop | Ruby: стиль + ошибки |
AI-assisted рефакторинг (2024-2025)
AI-инструменты помогают анализировать код и предлагать улучшения:
GitHub Copilot: Предлагает рефакторинги в реальном времени
Sourcegraph Cody: Понимает кодовую базу, предлагает изменения
Amazon CodeWhisperer: Рекомендации по оптимизации
Tabnine: Контекстные предложения
Управление зависимостями
| Инструмент | Что делает |
|---|---|
Dependabot | Автоматические PR для обновления зависимостей |
Renovate | Более гибкая альтернатива Dependabot |
Snyk | Поиск уязвимостей в зависимостях |
16. CI/CD и Feature Flags
Staging Environment
Рефакторинг никогда не должен идти сразу в продакшен. Staging environment позволяет:
Тестировать в условиях, близких к боевым
Проводить нагрузочное тестирование
Валидировать производительность
Ловить проблемы до пользователей
Feature Flags
Feature flags позволяют включать/выключать новый код без редеплоя:
// Пример с feature flag
if (feature_flags.is_enabled("new_checkout_flow")) {
return new_checkout_process(order);
} else {
return legacy_checkout_process(order);
}
Преимущества feature flags для рефакторинга
✅ Можно мержить незаконченный рефакторинг в main
✅ Постепенный rollout на % пользователей
✅ Быстрый rollback при проблемах
✅ A/B тестирование нового vs старого кода
Branching стратегии
| Стратегия | Когда использовать |
|---|---|
Feature branches + Feature flags | Рекомендуется для рефакторинга |
Trunk-based development | При высоком уровне тестов |
Long-lived branches | Избегать — merge hell |
17. Практическое руководство: шаг за шагом
Чек-лист перед рефакторингом
✅ Понимаю, что код делает (хотя бы на уровне black box)
✅ Есть тесты (или написаны characterization tests)
✅ Тесты проходят (зелёные)
✅ Есть версионный контроль
✅ Могу быстро откатить изменения
✅ Чёткая цель: что улучшаю и зачем
Алгоритм безопасного рефакторинга
Понять код: Прочитать, запустить, подебажить
Написать тесты: Characterization tests для текущего поведения
Убедиться, что тесты зелёные
Сделать маленькое изменение
Запустить тесты
Если зелёные — закоммитить
Если красные — откатить и разобраться
Повторить
Шаблон документирования рефакторинга
## Рефакторинг: [Название]
### Проблема
- Что не так с текущим кодом
- Как это влияет на разработку/пользователей
### Решение
- Что планируем сделать
- Какие техники используем
### Риски
- Что может пойти не так
- Как митигируем
### Тестирование
- Какие тесты написаны/обновлены
- Как проверить, что ничего не сломалось
### Rollback план
- Как откатить, если что-то пойдёт не так
### Метрики успеха
- Как измерим, что рефакторинг удался
18. Gilded Rose Kata: практика
Что такое Gilded Rose
Gilded Rose — это ката (упражнение) для практики рефакторинга, созданная специально для обучения. Представляет собой legacy-код с запутанной логикой обновления качества товаров в магазине.
Почему это хорошая практика
Код намеренно запутанный, но работающий
Есть спецификация поведения
Нужно добавить новую фичу, но сначала — рефакторинг
Доступна на многих языках
Рекомендуемый подход
Написать characterization tests
Добиться 100% покрытия
Рефакторить маленькими шагами
После рефакторинга — добавить новую фичу
Ресурс: Репозиторий Gilded Rose доступен на GitHub с версиями для 30+ языков.
Итоги
Рефакторинг легаси-кода — это не роскошь, а необходимость. Компании тратят 50% времени только на понимание существующего кода. Технический долг растёт как кредит с процентами. Но страх «всё сломать» парализует команды.
Ключевые принципы:
Legacy = код без тестов. Первый шаг — написать characterization tests
Маленькие шаги: Baby steps, частые коммиты, feature flags
Boy Scout Rule: Оставляй код чище, чем нашёл
Strangler Fig: Постепенная замена, не Big Bang rewrite
Данные для менеджмента: Velocity, bug rate, cycle time — переводите в деньги
Культура команды: Рефакторинг — нормальная часть работы, не «extra»
Приоритизация: Сначала то, что часто меняется и критично для бизнеса
Формула безопасного рефакторинга:
Тесты + Маленькие шаги + Версионный контроль + CI/CD = Уверенность
Понять → Покрыть тестами → Отрефакторить → Проверить → Закоммитить
Рефакторинг — это инвестиция. Да, он требует времени сейчас. Но он экономит многократно больше времени в будущем. И самое главное: это единственный способ не утонуть в техническом долге.
Финальная мысль: «Рефакторинг помогает нам перестать бояться собственного кода и избежать стыда, когда приходится его показывать кому-то другому.»
А лучшие вакансии для разработчиков ищите на hirehi.ru