Как сделать рефакторинг кода

Добавил пользователь Владимир З.
Обновлено: 10.09.2024

Книга 4 простых способа рефакторинга кода

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

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

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

Определение функций для повторяющихся задач

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

Функции предоставляют множество преимуществ, но с точки зрения рефакторинга сокращается объём кода, улучшается читаемость. Кроме того, если нужно обновить задачу, делать это понадобится только на одном участке — в определении функции.

Давайте рассмотрим пример, где нужно запросить длину и ширину прямоугольника для вычисления его площади.

Заметьте, что два блока почти идентичны. А что, если понадобится вычислить объём куба? Скорее всего мы скопируем цикл while, изменив имя переменной и приглашение к вводу.

После

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

Конструктор списков вместо цикла for

Конструктор списков — один из самых легендарных конструкторов Python. Конструктор списков является более чистой и быстрой реализацией в сравнении с многими простыми циклами for.

Существует множество преимуществ рефакторинга циклов for в конструкторы списков: код будет выполняться быстрее, существующие данные не будут меняться, кроме того, конструктор списков проще читать, как только вы к нему привыкаете.

Давайте рассмотрим два примера, один простой и второй немного посложнее.

В первом примере выберем нечётные числа из списка целых чисел.

В этом примере запустим цикл в my_numbers и используем оператор вычисления остатка, чтобы определить, нужно ли вставлять элемент в odd_numbers .

После рефакторинга

Подведём итог в этом примере: конструктор списков — это передача элементов в odd_numbers , перебор my_numbers , выполнение return (первый item ) и применение оператора if для фильтрации.

Можно создавать более сложные конструкторы списков, что даёт большие преимущества. Во втором примере предположим, что у нас есть двумерная матрица целых чисел и каждое значение мы хотим возвести в квадрат.

Мы должны использовать вложенный цикл for вместе с временной переменной для хранения каждой строки перед вставкой в окончательную переменную.

После рефакторинга

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

Логический оператор OR вместо условного оператора

Присвоение одного из двух значений может быть обработано с помощью простого оператора if:

Эти типы присвоений “или-или” традиционно могут выполняться с помощью условного оператора, объединяющего присвоения в один.

Структура условного оператора такова:

Когда выражение должно оценить, приводит ли “value-if-true” к булеву значению True , логический оператор OR может упростить трудно читаемый условный оператор.

После

Логический оператор OR пытается присвоить первое значение. Если первое значение приводит к False —None, пустая переменная и т.д.—используется второе значение.

Этот код значительно проще читать, он позволяет эффективно устанавливать значение по умолчанию при присвоении переменной.

Функция enumerate() вместо range()

Цикл for в Python может сбивать с толку, особенно, если вы привыкли работать с другими языками программирования. Вашим первым порывом будет создать индексную переменную и использовать её для перебора списка.

В результате часто используется функция range() . Этот приём не “в стиле” Python, в отличие от руководства по стилю и проверенных приёмов. Подробнее вы можете прочесть в моей статье “Перестаньте использовать range() в цикле for в Python”.

Если вам очень нужны индексы каждого значения, используйте функцию enumerate() : перебор будет производиться по фактическому списку, и независимая переменная будет не нужна.

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

После рефакторинга

Функция enumerate() принимает два аргумента: итерируемое и начальное значение счёта, а возвращает текущее порядковое значение и элемент в итерируемом. Примечание: временная переменная счёта идёт первой в цикле for, а начальное значение счёта идёт вторым в вызове функции. Это распространённая ошибка.

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

Рефакторинг и улучшение кода

Image by Free-Photos from Pixabay

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

Но написание плохого кода дорого обходится. Вам случалось оказываться в ситуации, когда вы просто не понимаете ваш собственный код спустя пару недель после его написания, и вам приходится тратить часы (если не дни), на попытки понять, что к чему?

Решение этой (невероятно) распространенной проблемы состоит в том, что нам нужно делать свой код как можно более понятным и информативным. Я бы сказал, что код должен быть понятен даже не-технарям. Пришла пора отбросить все наши самооправдания и улучшить качество нашего кода.

Писать чистый код не так уж и сложно. В этом руководстве вы найдете 5 простых подходов к улучшению кода (с практическими примерами).

Избавляемся от конструкций switch

Обычно мы используем switch, чтобы избежать создания слишком больших блоков if else if. Но конструкции switch слишком многословны, их сложно поддерживать и еще сложнее заниматься их отладкой. Они загромождают наш код и, по моему скромному мнению, имеют странный, неудобный синтаксис. При добавлении большего количества cases нам приходится вручную добавлять каждый блок case и break, а это способствует появлению ошибок.

Давайте рассмотрим пример конструкции switch:

Представьте, что нам нужно добавить больше блоков case. Количество кода, которое придется написать, станет довольно значительным. Вероятно, в конечном итоге мы начнем копировать и вставлять код, а все мы знаем, к чему это приводит.

Так как же избежать использования конструкций switch? Это можно сделать, используя объектные литералы. Объектный литерал прост, его легко писать, читать и поддерживать. Все мы привыкли к управлению объектами в JavaScript, и этот синтаксис намного чище, чем конструкция switch. Вот пример:

Примечание: как вы, наверное, заметили, мы объявляем объект pokemon вне функции, а не внутри. Это делается, чтобы объект не создавался каждый раз при запуске функции.

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

Вот как можно использовать map:

Как видите, при замене конструкций switch на объектный литерал или map наш код выглядит гораздо чище.

Делайте ваши условия наглядными

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

Взгляните на следующую конструкцию:

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

Как нам улучшить наше условие? Путем выделения его в функцию. Вот так:

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

Заменяйте вложенные условные операторы граничными операторами

Вложенные if-конструкции это одна из наихудших вещей, с которыми можно столкнуться в коде. Мне попадались if-ы, идущие на 10 уровней вглубь… Поверьте мне на слово: попытки разобраться в таком коде это просто кошмар. Вот пример вложенных условий if (только на три уровня в глубину, я ж не монстр):

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

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

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

Избегайте дублирования кода

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

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

После выделения цикла for в функцию getNewsContent наши функции getJavascriptNews, getRustNews и getGolangNews превратились в простые и понятные однострочники.

Дальнейший рефакторинг

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

Куда делись наши getJavascriptNews, getRustNews и getGolangNews? Мы заменили их функцией getNews, получающей вид новостей в качестве аргумента. Таким образом, не имеет значения, сколько еще видов новостей мы добавим, — мы в любом случае сможем пользоваться этой функцией. Это называется абстракцией и позволяет нам использовать функции повторно, а это чрезвычайно полезно. Абстрагирование это один из подходов, которые я чаще всего применяю в моем коде.

Бонус: сделайте цикл for более читаемым при помощи свойств ES6

Это последнее изменение, клянусь!

Циклы for не отличаются совершенной читабельностью. Но после введения функций массивов в ES6 мы можем в 95% случаев избежать использования циклов for. В нашем случае мы можем заменить исходный цикл при помощи Array.filter в комбинации с Array.map:

  • При помощи Array.filter мы возвращаем только те элементы, чьи типы соответствуют типу, переданному в качестве аргумента.
  • При помощи Array.map мы возвращаем только свойство content объекта Item, а не весь Item.

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

Функции должны делать только что-то одно

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

Примечание: поскольку обработчики для прослушивателей событий были не нужны в примере, я их удалил.

Давайте пройдемся по внесенным изменениям.

Для начала, мы избавились от блока if else при помощи граничного оператора. Затем мы выделили логику, необходимую для старта базы данных, в функцию initDatabase, а логику добавления прослушивателей событий — в функцию setListeners.

Логика вывода списка сотрудников немного более сложная, так что мы создали три функции: printEmployeeList, formatEmployeeList и getEmployeeList.

Функция getEmployeeList ответственна за осуществление запроса GET к employeeList.json и возврат ответа в формате json.

Затем он вызывается функцией printEmployeeList, которая принимает список сотрудников и передает его функции formatEmployeeList, которая форматирует и возвращает его. После этого список выводится.

Как видите, каждая из функций ответственна за что-то одно.

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

Заключение

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

Применяя 5 простых подходов, показанных в этом туториале, вы существенно повысите качество своего кода и, опосредованно, вашу продуктивность.

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

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

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

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

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

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

Правила рефакторинга

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

Самый важный урок, который должен преподать данный пример, это ритм рефакторинга: тестирование, малые изменения, тестирование, малые изменения, тестирование, малые изменения. Именно такой ритм делает рефакторинг быстрым и надежным.

Принципы рефакторинга

Рефакторинг (Refactoring): изменение во внутренней структуре программного обеспечения, имеющее целью облегчить понимание его работы и упростить модификацию, не затрагивая наблюдаемого поведения.

Производить рефакторинг (Refactor): изменять структуру программного обеспечения, применяя ряд рефакторингов, не затрагивая его поведения.

Рефакторинг не меняет видимого поведения программного обеспечения. Оно продолжает выполнять прежние функции. Никто — ни конечный

Без рефакторинга не обходится ни один действительно сложный и долгоживущий проект

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

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

Тем не менее, рефакторинга только в процессе разработки отдельных компонентов не достаточно. Если разрабатываемый компонент не изолирован, а взаимодействует с другими, то обычно есть необходимость в рефакторинге программных интерфейсов, через которые это самое взаимодействие реализуется.

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

Наиболее частые причины для рефакторинга:

  • дублирование кода;
  • длинные методы;
  • объёмные классы;
  • длинные списки параметров;
  • избыточные временные переменные;
  • классы данных;
  • несгруппированные данные;
  • несоблюдение стандартов кодирования.

Когда следует проводить рефакторинг?

В жизни каждой программы, по крайней мере, в жизни тех, что разрабатываются на заказ, наступает этап, когда основные функциональные требования заказчика, по мнению разработчика, выполнены, и программный продукт поступает на тестирование. А может быть даже в опытную эксплуатацию. В ходе тестирования, если у того, кто его проводит, руки растут из нужного места и мозги работают в правильном направлении, на разработчика начинает валиться большое число bug-ов, связанных с исключительными ситуациями, “защитой от дурака”, экстремальными объемами данных, неприемлемым быстродействием и так далее (идеально работающие программы сразу не пишутся). Разработчик старается быстро реагировать на вызовы судьбы и вносит большое количество локальных исправлений, а иногда и “заплат”, вследствие чего код теряет первоначальную стройность и сбалансированность. Вот в моменты между основными волнами наплывов претензий со стороны отдела технического контроля или просто ОТК и следует проводить рефакторинг кода: анализировать код и, используя ряд эффективных приемов, преобразовывать его к более согласованному и “прозрачному виду.” Естественно, что этап рефакторинга нельзя считать однократным.

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

Как мне кажется, отдельного внимания, помимо прочих, должны быть удостоены и те части кода, которые давно не редактировались (не были затронуты в процессе исправления ошибок или расширения функциональности), поскольку вряд ли они настолько невосприимчивы к вносимым вами изменениям, хотя и сохраняют корректное поведение. Но это уже ответ скорее не на вопрос “Когда уместно…”, а на вопрос “Где искать…”

Почему рефакторинг приносит результаты

Из-за чего бывает трудно работать с программами? Есть, как минимум, 4 причины:

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

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

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

Когда рефакторинг не нужен?

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

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

Другой случай, когда следует воздерживаться от рефакторинга, это близость даты завершения проекта. Рост производительности, достигаемый благодаря рефакторингу, проявит себя слишком поздно — после истечения срока. Правильна в этом смысле точка зрения Уорда Каннингема (Ward Cunningham). Незавершенный рефакторинг он сравнивает с залезанием в долги. Большинству компаний для нормальной работы нужны кредиты. Однако вместе с долгами появляются и проценты, то есть дополнительная стоимость обслуживания и расширения, обусловленная чрезмерной сложностью кода. Выплату каких-то процентов можно вытерпеть, но если платежи слишком велики, вы разоритесь. Важно управлять своими долгами, выплачивая их часть посредством рефакторинга.

Однако приближение срока окончания работ — единственный случай, когда можно отложить рефакторинг, ссылаясь на недостаток времени. Опыт работы над несколькими проектами показывает, что проведение рефакторинга приводит к росту производительности труда. Нехватка времени обычно сигнализирует о необходимости рефакторинга.

Рефакторинг vs Реинжиниринг?

Если рефакторинг кода не меняет поведения программы, то реинжиниринг на такое способен. Можно рассматривать реинжиниринг, как крайнюю форму рефакторинга, но мне кажется, что это не вполне корректно. Скорее, рефактиринг может стать причиной легкого реинжиниринга. Рассмотрим вариант, когда периодический рефакторинг в процессе интенсивного тестирования программного продукта может привести к реинженирингу:

Специалисты ОТК, а возможно, уже и пользователи (зависит от этапа жизненного цикла программного продукта) постоянно регистрируют ошибки, непосредственно связанные с особенностью принятых вами решений при проектировании программы. Возможно, вы некорректно выбрали шаблон проектирования в процессе разработки архитектуры вашей программы. Инспекция кода и периодический рефакторинг могут выявить такие места – они выглядят громоздкими, нелогичными и не поддаются общеизвестным правилам рефакторинга. Вы принимаете решение внести изменения в архитектуру программы, оцениваете последствия и грядущие изменения в ее поведении, согласуете и объявляете о планируемых изменениях и приступаете к реинжинирингу.

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

Рефакторинг vs Оптимизация

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

Разработка тестов

При проведении рефакторинга важным предварительным условием является наличие надежных тестов.

Правила разработки тестов

  • Потребность вносить изменения в существующий код
  • Необходимость строго придерживаться поставленной задачи
  • Покрывать код проверочными тестами

Признаки, что Вам нужен рефакторинга

  • Ваш программный продукт работает, но внесение новой функциональности иногда затягивается на недели;
  • В определенных местах Ваш код работает совершенно не так, как Вы того ожидали;
  • Вы часто ошибаетесь в сроках реализации поставленной задачи;
  • Вам приходится вносить однотипные изменения в разных местах.
  • Инкапсуляция поля (Encapsulate Field);
  • Выделение класса (Extract Class);
  • Выделение интерфейса (Extract Interface);
  • Выделение локальной переменной (Extract Local Variable);
  • Выделение метода (Extract Method);
  • Генерализация типа (Generalize Type);
  • Встраивание (Inline);
  • Введение фабрики (Introduce Factory);
  • Введение параметра (Introduce Parameter);
  • Подъём поля/метода (Pull Up);
  • Спуск поля/метода (Push Down);
  • Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism);

Рефакторинг очень существенно влияет на сопровождаемость проекта

Сначала учите науку программирования и. html'теорию. Далее выработаете свой программистский стиль. Затем забудьте все и просто программируйте.

Рефакторинг - один из способов создания кристально чистого кода

Определение и применение рефакторинга кода

Что такое рефакторинг кода понять несложно – определений в сети достаточно много. Наиболее удачное и полн.h.h.html'мой взгляд, в википедии, и не только потому, что оно исчерпывающее, но и ..html''у, что в нем рефакторинг противопоставляется таким этапам жизненного цикла программных продуктов, как оптимизация и реинжиниринг. Познакомиться с этим вариантом определения легко, набрав в строке интернет поиска слово "Рефакторинг" и открыв (скорее всего первую) ссылку на сайт свободной энциклопедии.

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

Когда уместно проводить рефакторинг кода?

В жизни каждой программы, по крайней мере, в жизни тех, что ра..html''тываются на заказ, наступает этап, когда основные функциональные требования заказчика, по мнению разработчика, выполнены, и программный продукт поступает на тестирование. А может быть даже в опытную эксплуатацию. В ходе тестирования, если у того, кто его проводит, руки растут из нужного места и мозги работают в правильном направлении, на разработчика начинает валиться большое число bug-ов, связанных с исключительными ситуациями, “защитой от дурака”, экстремальными объемами данных, неприемлемым быстродействием и так далее (идеально работающие программы сразу не пишутся). Разработчик старается быстро реагировать на вызовы судьбы и вносит большое количество локальных исправлений, а иногда и “заплат”, вследствие чего код теряет первоначальную стройность и сбалансированность. Вот в моменты между основными волнами наплывов претензий со стороны отдела технического контроля или просто ОТК и следует проводить рефакторинг кода: анализировать код и, используя ряд эффективных приемов, преобразовывать его к более согласованному и “прозрачному виду.” Естественно, что этап рефакторинга нельзя считать однократным.

Также, уместно проводить рефакторинг кода после добавления новой функциональности, поскольку.html'''е действия легко могут привести к необходимости провести ряд преобразований, связанных с манипуляцией классами и их элементами. Довольно часто новая функциональность является причиной извлечения новых методов или даже новых классов и/или переименования их, поскольку роль последних может быть расширена, уточнена или специализирована.

Как мне кажется, отдельного внимания, помимо прочих, должны быть удостоены и те части кода, которые давно не редактировались (не были затронуты в процессе исправления ошибок или расширения функциональности), поскольку вряд ли они настолько невосприимчивы к вносимым вами изменениям, хотя и сохраняют корректное поведение. Но это уже ответ скорее не на вопрос “Когда уместно…”, а на вопрос “Где искать…”

Кому может быть полезен рефакторинг кода?

read manual

Во-вторых, сложные программные компоненты часто разрабатываются совместно несколькими людьми. Инструментов для организации совместной разработки программных продуктов существует много: например это Rational Suite, в состав которого входит bag-tracker Clear-Quest и инструмент контроля версий программных компонентов Clear-Case. В Microsoft Visual Studio последних версий, например, есть замечательный инструмент Team Foundation Server. Понятно, что любой “зрелый” программный компонент должен сопровождаться подробным описанием его внешних программных интерфейсов (спецификаций), но нужно также понимать, что любой опытный разработчик, зная, как пишутся такие спецификации, захочет изучить логику работы вашего компонента, анализируя непосредственно его исходный код. Вот для этих целей хорошо было бы, чтобы ваш код был “читабельным”. Таким образом, можно сделать вывод, что рефакторинг кода может помочь ускорить процесс совместной разработки программного продукта.

Рефакторинг vs Реинжиниринг?

Обзор кода

Если рефакторинг кода не меняет поведения программы, то реинжиниринг на такое способен. Можно рассматривать реинжиниринг, как крайнюю форму рефакторинга, но мне кажется, что это не вполне корректно. Скорее, рефактиринг может стать причиной легкого реинжиниринга. Рассмотрим вариант, когда периодический рефакторинг в процессе интенсивного тестирования программного продукта может привести к реинженирингу:

Специалисты ОТК, а возможно, уже и пользователи (зависит от этапа жизненного цикла програм.h.html' продукта) постоянно регистрируют ошибки, непосредственно с. html'ные с особенностью принятых вами решений при проектировании программы. Возможно, вы некорректно выбрали шаблон проектирования в процессе разработки архитектуры вашей программы. Инспекция кода и периодический рефакторинг могут выявить такие места – они выглядят громоздкими, нелогичными и не поддаются общеизвестным правилам рефакторинга. Вы принимаете решение внести изменения в архитектуру программы, оцениваете последствия и грядущие изменения в ее поведении, согласуете и объявляете о планируемых изменениях и приступаете к реинжинирингу.

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

Рефакторинг vs Оптимизация

Ну тут совсем все легко, потому как рефакторинг кода и оптимизация кода преследуют разные цели, и, как это обычно бывает, оказывают противоположный эффект на читаемость кода, хотя и тот и другой не меняют логику работы программ.html'''процессе оптимизации программного кода главной целью является обеспечение приемлемой скорости выполнения (или рационального расходования памяти в ходе выполнения) критических участков - “узких мест” в программе. В жертву могут быть принесены не только логичность и “красота” программного кода, но и основные догмы объектно-ориентированного подхода. Результатами оптимизации могут стать и появление глобальных переменных, и “лишние” отрытые методы и свойства, раскрывающие детали реализации ваших классов и т.п. безобразия. На мой взгляд, нужно уделять особое внимание рефакторингу, а необходимость в оптимизации стараться сводить к минимуму за счет уместного использования качественных библиотек сторонних производителей.

Именование переменных, свойств, методов и функций

Именование переменных.

Данная тема не имеет прямого отношения к рефакторингу кода, но, тем не менее, оказывает немалое влияние на его читабельность. Каждый разработчик со временем вырабатывает свой стиль кодирования и, как следствие, использует свои правила именования лексем, частично или полность..html''мствованные из различных нотаций. Довольно часто используют соглашения так называемой венгерской нотации. Я не буду в этой статье перечислять все соглашения этой замечательной нотации, обсуждать ее плюсы и минусы, но сделаю акцент на основном, по моему мнению, преимуществе ее использования: обозначение переменной или константы, помимо ее семантики, также отражает ее тип и область видимости. Например: m_iIndex – переменная, член класса целочисленного типа; gc_bUseCache - глобальная константа булева типа и т.д. Согласитесь, это довольно серьезно может облегчить жизнь тому, кто пытается разобраться в чужом коде. Помимо использования соглашений венгерской нотации я также рекомендую следовать следующим правилам:

  • Наименования свойств и полей класса булева типа формировать с использованием модальных и вспомогательных глаголов в соответствии с их назначением, например: IsReadOnly , HasValue , CanRestore и т.д.;
  • Наименования методов, выполняющих какие-либо служебные, не связанные со спецификой вашей программы операции стараться формировать с использованием таких же служебных, часто используемых для обозначения смысла этих операций глаголов: UpdateView , EvaluateValue , RefreshContext и т.д.
  • При именовании методов стоит учитывать наименование класса и не дублировать его в наименовании этих методов, например: для обозначения методов открытия и закрытия соединения с базой данных класса DbConnection стоит выбрать имена Open и Close , а не OpenConnection и CloseConnection , соответственно. Исключением могут являться случаи, когда действие, выполняемое методом специфично или вторично по отношению к основному функционалу класса, например: методы работы с журналом событий OpenLog и CloseLog для того же класса DbConnection .
  • Если метод или свойство открытое ( public ), а его назначение нетривиально (в том смысле, что не может быть сформулировано одним или двумя словами типа GetResource или SaveChanges ), то скорее всего не стоит его именовать “склеиванием” сокращений нескольких слов типа GetNewClntProf – такой подход уместен для внутреннего использование, но не для метода, который “торчит наружу”, являясь частью открытого интерфейса - не все поймут правильно эту аббревиатуру, не говоря уже о том, что в разных языках (естественных) различные правила сокращения слов. Лучше не жалеть места и составить наименование, как конкатенацию всех слов целиком: GetNewClientProfile .
  • Для того, чтобы в контексте метода или функции отличать ее параметры от локальных переменных (глобальные переменные и члены класса и так выделяются префиксом типа m_ , c_ , g_ и т.д.) предлагаю имена этих локальных переменных начинать с подчеркивания “_” (естественно, если это позволяет синтаксис выбранного вами языка программирования) и дальше в соответствии с венгерской нотацией.

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

Построение SQL запросов и работа с базой данных.

Примеры программной Plug-in архитектуры.

Язык разметки XML и его расширения с примерами.

Языки HTML, XHTML и CSS с примерами разметки.

Основы веб-дизайна: решения типовых задач верстки.

Руководство по программированию на PHP для начинающих.

Шаблоны проектирования
Каталог шаблонов проектирования программных компонентов.

Рефакторинг кода
Каталог приемов рефакторинга программного кода.

Читайте также: