#refactoring
#рефакторинг
Вопрос:
Существует устаревшее приложение среднего размера (20 КБ LoC, 150 классов Java). Качество дизайна и кода очень низкое, нет модульных тестов, нет документации. Однако это работает.
Вас наняли для поддержки приложения. Существует список очень специфических ошибок, о которых сообщается надлежащим образом. Очень сложно понять, как их исправить. Время ограничено, вы должны начать устранять эти ошибки в течение нескольких недель (у вас просто нет времени сначала на глубокий рефакторинг). Как это сделать?
Комментарии:
1. По одной ошибке за раз? Это кажется более подходящим для программистов…
Ответ №1:
Начните с первой ошибки. Может быть, самый простой, может быть, самый приоритетный. Все, что имеет смысл для вашего магазина.
Не исправляйте это.
Вместо этого выясните, почему оно работает некорректно. Судя по вашему описанию, это вряд ли будет каким-то аккуратным, приятным методом модульного тестирования; вероятно, это где-то глубоко в какой-то запутанной логике. Найдите это.
Не исправляйте это.
Разработайте способ извлечения виновника. Может быть, это метод извлечения; может быть, это класс извлечения; может быть, поможет какой-то другой метод. Но сделайте это там, независимо от другого кода. Все еще сбой, просто с ним легче работать. Теперь напишите тест, который демонстрирует сбой.
Хорошо, теперь исправь это.
Что вы сделали? Вы выделили проблему, исправили ее, упростили работу с небольшим участком вашего кода и начали внедрять тестовое покрытие.
Вспеньте, промойте, повторите.
Комментарии:
1. Если повторять этот процесс бесконечно, то, как мне кажется, вы получаете код, организованный вокруг исправленных ошибок. Это кажется очень странной целью.
2. Вряд ли странно. Горячие точки, сбои, известные слабые места в вашем коде исправлены и очищены.
3. А как насчет часов, которые отсчитывают время вдоль side?
4. Эти часы — эта бомба замедленного действия, если хотите — тикают. Пока это продолжается, вы можете (а) провести масштабный рефакторинг и надеяться, что закончите вовремя, или (б) использовать поэтапный подход, который фокусируется на том, что, как вы знаете, не работает, и улучшает ваш код на каждом этапе пути. Простой выбор.
Ответ №2:
Я не думаю, что у вас хорошая ситуация.
Сначала я бы начал с «рефакторинга» задания. Дайте понять своему боссу, что ситуация очень сложная. Вы также должны дать понять, что, поскольку вы не несли ответственности за создание беспорядка, ему нужно сейчас взять на себя обязательство не возлагать на вас ответственность за неудачу, но что вы приложите к этому максимум усилий. Если он не готов взять на себя это обязательство в данных обстоятельствах, тогда я бы нашел другую работу.
Теперь вопрос в том, как действовать дальше. Что бы вы ни делали, вы должны находить проблемы в коде и по ходу дела упрощать их выполнение.
Сначала вам придется просмотреть код и получить некоторое представление о структуре. Везде, где, по вашему мнению, вы что-то понимаете, вставьте комментарий; там, где вы этого не понимаете, и это важно, вставьте комментарий с вопросом. Если можете, добавьте утверждение. В тех случаях, когда эти новые утверждения нарушаются, если их легко исправить, сделайте это; если нет, вы можете отсортировать их, просто удалив их или превратив в вопрос-комментарий. В этих комментариях, вопросах и утверждениях будут, по крайней мере, зафиксированы детали низкого уровня того, что вы (не) понимаете.
Я бы также получил инструмент, который позволит вам надежно применять рефакторинги переименования (акцент на последнем: вы не можете допустить, чтобы они нарушали код хуже, чем он есть). Яростное и неукоснительное переименование поможет стабилизировать словарный запас как для кода, так и для вас, и избавиться от плохих названий. И вы можете сделать это, просматривая / работая над кодом, с очень небольшими временными затратами и большим выигрышем в удобочитаемости.
Чтобы найти (потенциальный) источник ошибок, я бы использовал инструмент тестового покрытия. Такой инструмент сообщает вам, какой код был выполнен при запуске «теста». Творчески используя такой инструмент, вы можете запустить «тест» (ручной или автоматизированный, по мере необходимости), который выявляет ошибку; код, отображаемый инструментом покрытия тестированием, должен где-то содержать ошибку. Вы можете запускать другие «тесты», которые не обнаруживают ошибки; выполняемый ими код, который является общим для трассировки ошибок, скорее всего, не содержит ошибки.
Проблема в том, как вы можете вычислить эту «разницу» в выполняемом коде? Некоторые инструменты тестового покрытия помогут вам определить это. Моя компания (Semantic Designs) предлагает следующее: Инструменты покрытия тестов для многих языков, которые делают именно это. Обычно векторы тестового покрытия используются для отображения вашего кода с наложениями, показывающими покрытие. Наши инструменты позволят вам обрабатывать независимые наборы тестовых покрытий: intersected, diff’d, union’ed и т.д. понять взаимосвязь между тестами, которые создают векторы, и отобразить эти результаты, отображаемые поверх вашего кода. Таким образом, вы можете напрямую увидеть разницу между вектором тестового покрытия для ошибки и тестовым покрытием для не-ошибок.
Как только у вас появится представление о том, в чем ошибка, добавьте больше утверждений в соответствующий код и снова запустите тест, генерирующий ошибку. Те, которые срабатывают, являются индикаторами того, что вы приближаетесь.
Я бы изначально избегал проблем, для исправления которых требовался серьезный рефакторинг кода, поскольку у вас мало времени. (Очевидно, что вы не можете знать это очень хорошо, пока не поймете, в чем проблема; исследование — это неизбежные затраты). В той мере, в какой вы сможете устранить некоторые проблемы на ранней стадии, вы приобретете политические очки. Вы можете использовать их, чтобы выиграть больше времени и, следовательно, возможность провести больший рефакторинг.