Refactoring Legacy Code
Дмитрий Миндра
SDET, Unity Technologies (Ciklum)
@dmytromindra
О докладчике
2010 - Lohika
2012 - Microsoft
2013 - Unity Technologies
Когда-то был приличным
инженером, но 10 лет назад
связался с дотнетчиками,
выучил C#, занялся ООП,
скатился к TDD и
модульному тестированию.
Характер скверный.
Женат
Extreme Programming (XP)
SCRUM ЭРА
Что такое legacy code?
1. Это код без тестов
2. Код без спецификации
3. Код написанный очень давно и
неизвестно кем.
4. …
MakeFlagWavingBastardWaveHisFlagWhichIsTheProbablyTheLastThingHeWillEverDo()
Найдено в Carmageddon 1 debugging symbols dumped
Как появляется Legacy Code?
Как появляется legacy code?
• Гонка за фичами (нужно больше золота)
• Меняющиеся требования.
• Костыли и хаки.
• Ротация разработчиков.
• Отсутствие мыслей о завтрашнем дне (
сопровождении кода )
Золотое правило
• Работает – не трогай!
Зачем мы меняем код ?
• Нужно добавить фичу.
• Нужно пофиксить баг.
• Нужно улучшить производительность.
ВАЖНО!
• Legacy код – это всегда работающий
код, задействованный в
функционировании программной
системы.
Что делать?
• Переписать заново (как правило плохая
мысль)
• Найти новую работу …
• Сделать код «не legacy» кодом.
Учись, иначе т
Учись, студент! Иначе, всю
жизнь вот так будешь
только ключи подавать!
Самая популярная техника
работы с Legacy Code
Edit and pray
С чего начать ?
• Определить что именно нужно менять
• Определить какие тесты нужны
• Запустить и проверить
• Написать тесты
• Внести изменения
С чего начать ?
• Определить что именно нужно менять
– Старый код бывает очень сложно понять
– Изменения могут быть сильно
распределены по коду
• Определить какие тесты нужны
• Запустить и проверить
• Написать тесты
• Внести изменения
С чего начать ?
• Определить что именно нужно менять
• Определить какие тесты нужны– Мы хотим убедиться, что код работает так же,
как работал до вмешательства.
– Есть ли механизм для мониторинга результатов.
– Мы не боимся долгих и сложных тестов на этом этапе!
• Запустить и проверить
• Написать тесты
• Внести изменения
Approval Tests
1. Сериализуем результат в текст
2. Сравниваем с эталоном
http://approvaltests.sourceforge.net
С чего начать ?
• Определить что именно нужно менять
• Определить какие тесты нужны
• Запустить и проверить
– Можем ли мы создать класс/вызвать метод в тесте?
– Можем ли мы получить результат вычислений?
• Написать тесты
• Внести изменения
Seams
• Швы – места, позволяющие менять
поведение программы не меняя код в
этом самом месте.
• Швы бывают объектные и линковочные
Sensing and Separation
• Sensing – мы меняем код для того,
чтобы получить доступ к результатам
вычислений.
• Separation – мы меняем код для того,
чтобы получить создать класс или
вызвать метод внутри теста.
Separation
В данном случае мы будем бороться за право создать экземпляр.
Самый простой рефакторинг – это добавить конструктор по умолчанию.
Separation
Старый код часто нарушает принцип DI
Избавляемся от зависимости
• Пожалуй самая распространенная
техника – Extract Interface &
Parameterize Constructor.
Extract Interface
Сначала избавимся от очень общего названия Sensor
Затем извлечем интерфейс Sensor
Parameterize Constructor
Конструктор по умолчанию все еще создает зависимость,
но теперь есть возможность подменить ее в тесте.
Extract and Override (шаг 1)
Было:
Стало:
Factory Method
Extract and Override (шаг 2)Factory Method
Почему Extract and Override?
• Legacy code – это зона риска. Мы
стараемся менять его минимальными
безопасными шагами (baby steps).
Шаг 1: Добавить метод
Шаг 1: Добавить методПопробуем обернуть вызов source.Read() методом Modify()
Это безопасная операция с минимальной модификацией
кода.
Шаг 2: Перегрузить его
Безопасно ли поменять private на protected? Вполне!
Безопасно ли сделать метод virtual? Вполне!
Теперь мы можем переопределить это поведение в
наследнике операцией, не меняющей исходный код
тестируемого класса.
Шаг 2: Перегрузить его
Extract and Override3rd party
Ох уж эти 3rd party, которые так сложно тестировать.
Extract
Override
Sensing with Extract and Override
С чего начать ?
• Определить что именно нужно менять
• Определить какие тесты нужны
• Запустить и проверить
• Написать тесты
– Эти тесты больше похожи на приемочные тесты.
– Они могут быть медленными, могут обращаться к внешним сервисам и базам данных
– Главная цель этих тестов определить работает ли старый код так же, как работал до вмешательства.
• Внести изменения
С чего начать ?
• Определить что именно нужно менять
• Определить какие тесты нужны
• Запустить и проверить
• Написать тесты
• Внести изменения и выполнить настоящий рефакторинг
– Когда код покрыт тестами он уже формально не является легаси кодом.
– Его можно рефакторить и править.
Вопросы
?
Что почитать?
Michael C. Feathers “Working Effectively
With Legacy Code”