Рефакторинг: как улучшить исходный код

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

В процессе рефакторинга ставится вопрос о том, какая проблема в коде должна быть решена с помощью какого метода. Рефакторинг считается одной из основ при изучении кода и приобретает все большее значение. Какие методы используются для этого и каковы их преимущества и недостатки?

Что такое рефакторинг?

Программирование программного обеспечения — это длительный процесс, в котором могут участвовать несколько разработчиков. В ходе этой работы написанный исходный код часто пересматривается, изменяется и расширяется. В результате нехватки времени или устаревшей практики в исходном коде могут накапливаться неуместные участки. Они известны как «запахи кода». Эти слабые места, накапливающиеся со временем, ставят под угрозу удобство использования и совместимость программы. Чтобы предотвратить эту постепенную эрозию и ухудшение состояния программного обеспечения, необходим рефакторинг.

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

Этот процесс намного экономичнее, чем подготовка совершенно новой структуры кода. Особенно в итеративной и инкрементальной разработке программного обеспечения, а также в гибкой разработке программного обеспечения рефакторинг играет важную роль, поскольку программистам часто приходится изменять программное обеспечение в этих циклических моделях. В этом контексте рефакторинг является фиксированным этапом рабочего процесса.

Когда исходный код портится: код-спагетти

Во-первых, важно понять, как код может стареть и превращаться в спагетти-код. Будь то из-за нехватки времени, недостатка опыта или нечетких инструкций, программирование кода может привести к потере функциональности в результате неоправданно сложных команд. Код ухудшается тем больше, чем быстрее и сложнее область применения.

Код-спагетти относится к запутанному, нечитаемому исходному коду, который может быть интерпретирован программистами только с большим трудом. Простые примеры запутанного кода включают лишние команды перехода (GOTO), которые предписывают программе переходить назад и вперед в исходном коде, или ненужные циклы for/while и команды if.

Проекты, в которых участвует много разработчиков программного обеспечения, особенно подвержены неясному исходному коду. Когда код проходит через множество рук и если оригинал уже содержит некоторые слабые места, трудно избежать растущего беспорядка, возникающего в результате «обходных решений», что приводит к необходимости дорогостоящего пересмотра кода. В тяжелых случаях «спагетти-код» может поставить под угрозу всю разработку программного обеспечения. Если проблема зашла так далеко, может быть даже слишком поздно для рефакторинга кода.

Запахи кода и гниение кода не столь катастрофичны. Со временем код может начать пахнуть — метафорически — всеми своими неуместными участками. Трудные для понимания части становятся еще хуже, когда другие программисты вмешиваются или добавляют новые строки. Если не провести рефакторинг при первых признаках запаха кода, исходный код будет постепенно терять функциональность в результате гниения кода.

Цель рефакторинга

Целью рефакторинга является простое достижение лучшего кода. Эффективный код позволяет лучше интегрировать новые элементы кода, не внося новых ошибок. Программисты, которые могут без труда читать код, смогут быстрее ознакомиться с разрабатываемым приложением и легче устранить или избежать ошибок. Еще одна цель рефакторинга — улучшить анализ ошибок и сопровождаемость программного обеспечения. Таким образом, работа программистов, просматривающих код, значительно упрощается.

Какие источники ошибок устраняет рефакторинг?

Техники, применяемые при рефакторинге, столь же разнообразны, как и ошибки, которые они призваны устранить. По сути, рефакторинг кода определяется его ошибками и включает в себя шаги, необходимые для сокращения или устранения того или иного подхода к решению. Источники ошибок, которые могут быть устранены с помощью методов рефакторинга, включают:

  • Запутанный или избыточный код: Командные строки и блоки настолько длинные, что внешние программисты не смогут понять внутреннюю логику программного обеспечения.
  • Дублирование кода (избыточность): Непонятный код часто содержит дубликаты, которые приходится менять отдельно в каждом случае при сопровождении, тем самым теряя время и ресурсы.
  • Чрезмерные списки параметров: Объекты не назначаются непосредственно методу, но их атрибуты передаются в списке параметров.
  • Классы со слишком большим количеством функций: Классы со слишком большим количеством функций, определенных как методы — также известные как объекты-боги — делают настройку программного обеспечения практически невозможной.
  • Классы со слишком малым количеством функций: Классы, в которых так мало функций, определенных как методы, что они не нужны.
  • Слишком общий код с особыми случаями: Функции со слишком специфическими особыми случаями, которые почти никогда не встречаются — если вообще встречаются — и поэтому затрудняют добавление необходимых расширений.
  • Средний человек: Отдельный класс действует как «посредник» между методами и различными классами, вместо того чтобы направлять вызовы методов непосредственно в класс.

Какой подход предполагает рефакторинг?

Рефакторинг всегда следует проводить перед изменением функции программы. В идеале он включает в себя очень маленькие шаги, а изменения кода проверяются с помощью таких процессов разработки программного обеспечения, как разработка на основе тестирования (TDD) и непрерывная интеграция (CI). В двух словах, TDD и CI означают непрерывное тестирование небольших новых участков кода, которые программисты собирают, интегрируют и тестируют с точки зрения их функциональности — часто с помощью автоматизированного тестирования.

Как правило, изменяйте программу только небольшими шагами внутри, не затрагивая внешние функции. После каждого изменения, по возможности, следует запускать автоматизированное тестирование.

Какие техники существуют

Существует целый ряд техник рефакторинга. Полный обзор можно найти во всеобъемлющей книге по рефакторингу Мартина Фаулера и Кента Бека: Refactoring: Improving the Design of Existing Code. Вот краткое резюме:

Красно-зеленая разработка

Красно-зеленая разработка — это метод гибкой разработки программного обеспечения, основанный на тестировании. Он используется, когда новая функция должна быть интегрирована в существующий код. Красным цветом обозначается первый прогон тестов перед внедрением новой функции в код. Зеленым цветом обозначается максимально простой участок кода, необходимый для функции, чтобы пройти тест. В результате расширение готовится с постоянными прогонами тестов, чтобы отсеять дефектный код и увеличить функциональность. Красно-зеленая разработка обеспечивает основу для непрерывного рефакторинга в непрерывной разработке программного обеспечения.

Ветвление через абстракцию

Этот метод рефакторинга описывает постепенное изменение системы и преобразование старого, внедренного кода в новые, интегрированные участки. Ветвление через абстракцию обычно используется для больших приложений, в которых задействованы иерархии классов, наследование и извлечение. Реализуя абстракцию, которая остается связанной со старой реализацией, другие методы и классы могут быть связаны с абстракцией, а функциональность старого участка кода может быть заменена абстракцией.

Это часто происходит с помощью методов pull-up или push-down. Они связывают новую, лучшую функцию с абстракцией и передают на нее ссылки. При этом они либо перемещают подкласс в более высокий класс (pull-up), либо разделяют более высокий класс на подклассы (push-down).

Затем можно удалить старые функции без ущерба для общей функциональности. Благодаря этим небольшим изменениям система работает без изменений, пока вы постепенно, раздел за разделом, заменяете неэлегантный код на аккуратный.

Компиляция методов

Рефакторинг призван сделать методы кода как можно более понятными. В идеале внешние программисты должны иметь возможность понять внутреннюю логику метода при чтении кода. Существует несколько различных техник для эффективной компиляции методов. Цель каждой из них — согласовать методы, удалить излишества и разбить слишком длинные методы на отдельные секции, тем самым открывая их для будущих изменений.

К таким техникам относятся:

  • извлечение методов
  • инкрустация методов
  • Удаление временных переменных
  • Замена временных переменных методом запроса
  • Внедрение описательных переменных
  • Разделение временных переменных
  • Удаление присвоений переменным параметров
  • Замена метода объектом метода
  • Замена алгоритма

Перемещение атрибутов между классами

Чтобы улучшить код, необходимо перемещать атрибуты или методы между классами. Здесь используются следующие приемы:

  • Переместить метод
  • Переместить атрибут
  • Извлеченный класс
  • Инлайн-класс
  • Скрыть делегат
  • Удалить класс в середине
  • Внедрить внешний метод
  • Ввести локальное расширение

Организация данных

Этот метод направлен на разделение данных на классы и сохранение их как можно более четкими и ясными. Вы должны удалить ненужные связи между классами, которые ухудшают функциональность программного обеспечения в случае незначительных изменений, и разделить их на последовательные классы.

Примеры приемов включают:

  • инкапсуляция доступа к собственным атрибутам
  • Замена собственных атрибутов ссылкой на объект
  • Замена значения ссылкой
  • Замена ссылки значением
  • Связывание наблюдаемых данных
  • Инкапсуляция атрибутов
  • Замена набора данных классом данных

Упрощение условных выражений

При рефакторинге следует максимально упростить условные выражения. Для этого можно использовать следующие приемы:

  • Снятие условий
  • Слияние условных выражений
  • Объединение повторяющихся инструкций в условных выражениях
  • Удаление управляющих переключателей
  • Замена вложенных условий защитными предложениями
  • Замена различий между случаями полиморфизмом
  • Внедрение нулевых объектов

Упрощение запросов методов

Запросы методов можно выполнять быстрее и проще, используя, например, следующие методы:

  • Переименование методов
  • Добавление параметров
  • Удаление параметров
  • Замена параметров явными методами
  • Замена кодов ошибок исключениями

Пример рефакторинга: переименование методов

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

До:

String getPostalCode() {
	return (theOfficePostalCode+“/“+theOfficeNumber);
}
System.out.print(getPostalCode());

После:

String getOfficePostalCode() {
	return (theOfficePostalCode+“/“+theOfficeNumber);
}
System.out.print(getOfficePostalCode());

Рефакторинг: преимущества и недостатки

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

В целом, при рефакторинге вводите новые функции только тогда, когда существующий исходный код должен остаться неизменным. Изменяйте исходный код — т.е. проводите рефакторинг — только тогда, когда вы не добавляете никаких новых функций.

Оцените статью
cdelat.ru
Добавить комментарий