Что такое рефакторинг программного кода. Что такое рефакторинг кода? Основные принципы и правила рефакторинга

04.12.2023

Концепция «рефакторинга» (refactoring) возникла в кругах, связанных со Smalltalk, но вскоре нашла себе дорогу и в лагеря приверженцев других языков программирования. Поскольку рефакторинг является составной частью разработки структуры приложений (framework development), этот термин сразу появляется, когда «структурщики» начинают обсуждать свои дела. Он возникает, когда они уточняют свои иерархии классов и восторгаются тем, на сколько строк им удалось сократить код. Структурщики знают, что хорошую структуру удается создать не сразу - она должна развиваться по мере накопления опыта. Им также известно, что чаще приходится читать и модифицировать код, а не писать новый. В основе поддержки читаемости и модифицируемости кода лежит рефакторинг - как в частном случае структур (frameworks), так и для программного обеспечения в целом.

Так в чем проблема? Только в том, что с рефакторингом связан известный риск. Он требует внести изменения в работающий код, что может привести к появлению трудно находимых ошибок в программе. Неправильно осуществляя рефакторинг, можно потерять дни и даже недели. Еще большим риском чреват рефакторинг, осуществляемый без формальностей или эпизодически. Вы начинаете копаться в коде. Вскоре обнаруживаются новые возможности модификации, и вы начинаете копать глубже. Чем больше вы копаете, тем больше вскрывается нового и тем больше изменений вы производите. В конце концов, получится яма, из которой вы не сможете выбраться. Чтобы не рыть самому себе могилу, следует производить рефакторинг на систематической основе. В книге «Design Patterns» сообщается, что проектные модели создают целевые объекты для рефакторинга. Однако указать цель - лишь одна часть задачи; преобразовать код так, чтобы достичь этой цели, - другая проблема.

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

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

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

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

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

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

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

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

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

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

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

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

Зачем нужно проводить рефакторинг?

  • Рефакторинг улучшает композицию программного обеспечения
  • Рефакторинг облегчает понимание программного обеспечения
  • Рефакторинг помогает найти ошибки
  • Рефакторинг позволяет быстрее писать программы

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

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

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

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

Из-за чего бывает трудно работать с программами? В данный момент мне приходят в голову четыре причины:

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

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

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

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

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

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

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

Рефакторинг и проектирование

Рефакторинг играет особую роль в качестве дополнения к проектированию. Если заранее подумать об архитектуре программы, то можно избежать последующей дорогостоящей переработки. Многие считают, что проектирование важнее всего, а программирование представляет собой механический процесс. Аналогией проекта служит технический чертеж, а аналогией кода - изготовление узла. Но программа весьма отличается от физического механизма. Она значительно более податлива и целиком связана с обдумыванием. Как говорит Элистер Кокберн (Alistair Cockburn):
«При наличии готового дизайна я думаю очень быстро, но в моем мышлении полно пробелов».

Существует утверждение, что рефакторинг может быть альтернативой предварительному проектированию. В таком сценарии проектирование вообще отсутствует. Первое решение, пришедшее в голову, воплощается в коде, доводится до рабочего состояния, а потом обретает требуемую форму с помощью рефакторинга. Такой подход фактически может действовать. Мне встречались люди, которые так работают и получают в итоге систему с очень хорошей архитектурой. Тех, кто поддерживает «экстремальное программирование» [ Beck , XP ], часто изображают пропагандистами такого подхода.
Подход, ограничивающийся только рефакторингом, применим, но не является самым эффективным. Даже «экстремальные» программисты сначала разрабатывают некую архитектуру будущей системы. Они пробуют разные идеи с помощью CRC-карт или чего-либо подобного, пока не получат внушающего доверия первоначального решения. Только после первого более или менее удачного «выстрела» приступают к кодированию, а затем к рефакторингу. Смысл в том, что при использовании рефакторинга изменяется роль предварительного проектирования. Если не рассчитывать на рефакторинг, то ощущается необходимость как можно лучше провести предварительное проектирование. Возникает чувство, что любые изменения проекта в будущем, если они потребуются, окажутся слишком дорогостоящими. Поэтому в предварительное проектирование вкладывается больше времени и усилий - во избежание таких изменений впоследствии.
С применением рефакторинга акценты смещаются. Предварительное проектирование сохраняется, но теперь оно не имеет целью найти единственно правильное решение. Все, что от него требуется, - это найти приемлемое решение. По мере реализации решения, с углублением понимания задачи становится ясно, что наилучшее решение отличается от того, которое было принято первоначально. Но в этом нет ничего страшного, если в процессе участвует рефакторинг, потому что модификация не обходится слишком дорого.
Рефакторинг предоставляет другой подход к рискам модификации. Возможные изменения все равно надо пытаться предвидеть, как и рассматривать гибкие решения. Но вместо реализации этих гибких решений следует задаться вопросом: «Насколько сложно будет с помощью рефакторинга преобразовать обычное решение в гибкое?» Если, как чаще всего случается, ответ будет «весьма несложно», то надо просто реализовать обычное решение.
Рефакторинг позволяет создавать более простые проекты, не жертвуя гибкостью, благодаря чему процесс проектирования становится более легким и менее напряженным. Научившись в целом распознавать то, что легко поддается рефакторингу, о гибкости решений даже перестаешь задумываться. Появляется уверенность в возможности применения рефакторинга, когда это понадобится. Создаются самые простые решения, которые могут работать, а гибкие и сложные решения по большей части не потребуются.

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

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

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

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

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

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

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

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

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

Проблемы рефакторинга

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

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

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

Методы рефакторинга

  • Инкапсуляция поля (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);
  • и так далее;

Рефакторинг кода

При создании приложений многие разработчики сначала заботятся об их функциональности, а когда она обеспечена, переделывают приложения таким образом, чтобы они были более управляемыми и удобочитаемыми. Это называется рефакторингом (refactoring) . Под рефакторингом понимается процесс переделки кода для повышения удобочитаемости и производительности приложений, а также обеспечения безопасности типов и приведения кода к такому виду, в котором он лучше соответствует рекомендуемым приемам объектно-ориентированного программирования. К счастью, теперь в Visual Studio 2010 можно достаточно хорошо автоматизировать этот процесс.

За счет использования меню Refactor (Рефакторинг) , которое становится доступным при открытом файле кода, а также соответствующих клавиатурных комбинаций быстрого вызова, смарт-тегов (smart tags) и/или вызывающих контекстные меню щелчков, можно существенно видоизменять код с минимальным объемом усилий. В следующей таблице перечислены некоторые наиболее распространенные приемы рефакторинга, которые распознаются в Visual Studio 2010:

Возможности рефакторинга кода
Прием рефакторинга Описание
Extract Method
(Извлечение метода)
Позволяет определять новый метод на основе выбираемых операторов программного кода
Encapsulate Field
(Инкапсуляция поля)
Позволяет превращать общедоступное поле в приватное, инкапсулированное в форму свойство C#
Extract Interface
(Извлечение интерфейса)
Позволяет определять новый тип интерфейса на основе набора существующих членов типа
Reorder Parameters
(Переупорядочивание параметров)
Позволяет изменять порядок следования аргументов в члене
Remove Parameters
(Удаление параметров)
Позволяет удалять определенный аргумент из текущего списка параметров
Rename
(Переименование)
Позволяет переименовывать используемый в коде метод, поле, локальную переменную и т.д. по всему проекту

Чтобы увидеть процесс рефакторинга в действии, давайте модифицируем метод Main(), добавив в него следующий код:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string args) { // Настраиваем консольный интерфейс (CUI) Console.Title = "Мое приложение"; Console.ForegroundColor = ConsoleColor.Yellow; Console.BackgroundColor = ConsoleColor.Blue; Console.WriteLine("Привет, это мой проект!"); Console.BackgroundColor = ConsoleColor.Black; Console.ReadLine(); } } }

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

Для этого выделите в окне редактора все содержащиеся внутри Main() операторы, кроме последнего вызова Console.ReadLine() , и щелкните на выделенном коде правой кнопкой мыши. Выберите в контекстном меню пункт Refactor --- Extract Method (Рефакторинг --- Извлечь метод).

После этого метод Main() станет вызывать новый только что сгенерированный метод MyConfigCUI(), внутри которого будет содержаться выделенный ранее код:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string args) { //Настраиваем консольный интерфейс (CUI) MyConfigCUI(); Console.ReadLine(); } private static void MyConfigCUI() { Console.Title = "Мое приложение"; Console.ForegroundColor = ConsoleColor.Yellow; Console.BackgroundColor = ConsoleColor.Blue; Console.WriteLine("Привет, это мой проект!"); Console.BackgroundColor = ConsoleColor.Black; } } }

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

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

Анализ и рефакторинг для создания чистого кода

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

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

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

Операция улучшения кода происходит примерно в следующих стадиях:

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

Непрерывный процесс управления качеством

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

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

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

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

Для примера эффективности рефакторинга существующего кода подсчитываем члены и операторы: (x - 1) * (x + 1) = x 2 - 1. Четыре термина против трех. Три оператора против двух. Однако выражение левой стороны проще понять, потому что оно использует более простые операции. Кроме того, он предоставляет больше информации о структуре функции f (x) = x 2 - 1, так как корни +/- 1, что было бы трудно определить, просто «глядя» с правой стороны.

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

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

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

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

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

Методы исправления:

  1. Перемещение класса. Класс находится в неправильном пакете, поэтому его следует перенести в другой пакет, где он лучше подходит.
  2. Извлечение. Длинный метод необходимо разбить на этапы, чтобы повысить читаемость и удобство обслуживания. Раздел кода с одной логической задачей заменяется вызовом на новый метод.
  3. Экстракция суперкласса. Существующий класс предоставляет функциональные возможности, которые необходимо каким-то образом изменить. Абстрактный класс вводится, как родитель текущего класса, а затем общее поведение «подтягивается» к этому новому родителю.
  4. Замена условного значения с полиморфизмом. Методы в классе могут проверять некоторое значение (если или оператор switch), чтобы определить правильное действие для выполнения.

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

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

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

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

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

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

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

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

Автоматизация процесса

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

  1. Система, из которой реорганизованный код является частью, может быть быстро восстановлена.
  2. Существуют автоматические «регрессионные» тесты, которые можно часто запускать.

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

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

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

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

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

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

До Visual Studio 2012 большинство этих видов анализа и тестирования кода требовали сторонних инструментов и ручных задач сборки, тестирования, анализа, повтора для разработчика. Сегодня Visual Studio имеет довольно прочные инструменты для анализа. Кроме того, есть отличные инструменты, которые помогут разработчику углубиться в приложение для тестирования производительности и оптимизации, шаблонов проектов, которые имеют эффективные зависимости и встроенные тестовые среды, а также надежные инструменты для интеграции автоматизированного анализа и тестирования в рабочих процессах сборки и выпуска.

Комплексный набор встроенных инструментов для рефакторинга улучшения проекта существующего кода был сначала сгруппирован в концентратор производительности и диагностики в Visual Studio 2013, который был дополнительно усовершенствован и расширен в окне «Отладка производительности и диагностики» и «Отсканированные инструменты» в «Визуал Студио» 2015.

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

Пользователь найдет информацию о сборе данных и профилировании во время выполнения метода не только для традиционных приложений.NET Framework, но также для продуктов JavaScript, ASP.NET и веб-сайтов, высокопроизводительных вычислений (HPC) и тестирования нагрузки.

Другим инструментом, которым с удовольствием пользуются разработчики, выступает рефакторинг кода c PerfView для анализа производительности. Моррисон является старшим архитектором в Microsoft и написал PerfView для внутреннего анализа производительности и настройки командами, создающими.NET Framework и Visual Studio. Теперь это инструмент с который по-прежнему находится в активной разработке.

Дополнительные механизмы для профилирования и отладки

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

  1. Jains dotTrace Profiler помогает отслеживать время выполнения, сбор мусора, распределение рабочей нагрузки, производительность ввода-вывода. Есть 10-дневная пробная версия, доступная для выполнения пробных шагов.
  2. Redgate ANTS Performance Profiler - еще один популярный инструмент для проектов на базе.NET Framework обеспечивает такой же анализ синхронизации кода, как и другие инструменты, но также углубляется в производительность запросов к базе данных с поддержкой расширенного профилирования доступа к данным с поддержкой Oracle, MySQL, и PostgreSQL.
  3. DevExpress CodeRush - еще один инструмент анализа и рефакторинга для баз данных C #, Visual Basic и XAML. Инструменты анализа CodeRush не только работают с основными решениями, но также имеют встроенную интегральную тестовую интеграцию, поддерживающую рамки NUnit, xUnit, MSpec и MSTest, а также тестовые примеры CoreCLR в среде DNX.
  4. Microsoft Code Analysis 2017 дает встроенный доступ к более чем 100 наиболее популярным правилам FxCop в качестве живых анализаторов. Анализаторы смотрят код C # или Visual Basic по мере ввода и предоставляют советы по производительности, безопасности и лучшим практикам, а также доступ к словарю быстрого исправления кода.
  5. Microsoft DevSkim - это более комплексная и гибкая структура модулей и анализаторов кода, ориентированных на встроенный анализ безопасности кода при вводе. Потенциальные проблемы безопасности выделяются в коде ссылками на дополнительную информацию одним кликом к безопасному альтернативному коду.

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

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

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

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

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

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

Энциклопедичный YouTube

    1 / 5

    ✪ Рефакторинг кода

    ✪ Признаки плохого программиста

    ✪ Основа рефакторинга:: SOLID:: Single Respnosibility:: Spring

    ✪ Знакомство с JavaScript #8 - Рефакторинг

    ✪ Книги для программистов Java Enterprise

    Субтитры

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

Цель рефакторинга - сделать код программы более легким для понимания; без этого рефакторинг нельзя считать успешным.

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

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

Причины применения рефакторинга

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

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

Признаки плохого кода

Во многом при рефакторинге лучше полагаться на интуицию, основанную на опыте. Тем не менее имеются некоторые видимые проблемы в коде (англ. code smells ), требующие рефакторинга:

  1. длинный метод;
  2. большой класс;
  3. длинный список параметров;
  4. «жадные» функции - это метод, который чрезмерно обращается к данным другого объекта;
  5. избыточные временные переменные;
  6. классы данных;
  7. несгруппированные данные.

Рефакторинг кода

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

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

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

Методы рефакторинга

Выделение метода (Extract Method)

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

Перемещение метода (Move Method)

Перемещение метода применяется по отношению к методу, который чаще обращается к другому классу, чем к тому, в котором сам располагается.

Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism)

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

Основные принципы:

Проблемы, возникающие при проведении рефакторинга

  • проблемы, связанные с базами данных;
  • проблемы изменения интерфейсов;
  • трудности при изменении дизайна.

Мне нравится рефакторинг. Нет, не так. Я люблю рефакторинг. Не, даже не так. Я чертовски люблю рефакторинг.
Я не переношу плохой код и плохую архитектуру. Меня коробит, когда я пишу новую фичу, а в соседнем классе творится полный бардак. Я просто не могу смотреть на печально названные переменные. Иногда перед сном я закрываю глаза и представляю, что можно было бы улучшить в проекте. Иногда я просыпаюсь в три часа ночи и иду к ноутбуку, чтобы что-нибудь поправить. Мне хочется, чтобы на любой стадии разработки код был не просто кодом, а произведением искусства, на которое приятно смотреть, с которым приятно работать.

Если вы хоть немного разделяете мои ощущения, то нам есть о чём поговорить. Дело в том, что со временем что-то внутри меня начало подсказывать, что рефакторить всё подряд, везде и всё время - не самая лучшая идея. Поймите меня правильно, код должен быть хорошим (а лучше бы ему быть идеальным), но в условиях суровой реальности не всегда разумно постоянно заниматься улучшением кода. Я вывел для себя несколько правил о своевременности рефакторинга. Если у меня начинают чесаться руки что-нибудь улучшить, то я оглядываюсь на эти правила и начинаю думать: «А действительно ли сейчас тот момент, когда нужно нарефакторить?». Давайте порассуждаем о том, в каких же случаях рефакторинг уместен, а в каких - не очень.


Дисклеймер. Скорее всего, многим захочется после прочтения поста сразу сказать: «Да это уже 600 раз обсуждалось!» или «Это же настолько очевидно, зачем же об этом писать?». Возможно, вы и правы, но только вот какой момент: в окружающем мире по-прежнему творится хаос. Вроде бы всем всё понятно, но на деле получается, что не так уж и понятно. Поэтому я думаю, что не будет слишком вредно ещё разок взглянуть на эту тему. Но если конкретно у вас проблем с рефакторингом нет, то можете просто пропустить этот пост, у вас уже всё хорошо.

Слишком ранний рефакторинг

Можете ли вы припомнить, когда у вас последний раз было постоянное ТЗ, которое месяцами не менялось? У меня вот такое вспомнить не очень получается. Мы живём в реальном мире, требования всё время меняются. Причём это не обязательно внешние требования - это могут быть ваши собственные требования к проекту. Поясню мысль на примере: допустим, вы взяли задачку среднего размера на один-два дня. Первые несколько классов уже написаны, но запустить пока нечего - идёт процесс написания суровой архитектурной части. И тут вы замечаете, что одна из частей проекта написана не особо универсально: «А вот если через полгода понадобится сделать X, то все будут страдать». Вполне разумно, что вам не хочется отправлять в репозиторий хреновый код, чтобы другие разработчики потом вспоминали вас плохим словом. И вы начинаете рефакторить ещё не готовую фичу . Иногда это оправдано, но на подобном пути следовало бы повесить табличку «ОПАСНОСТЬ». Вот поправите вы одну штуку, потом другую, потом третью. Неделя прошла, фича всё ещё не запускается, а вы говорите: «Как-то всё неправильно сделано. Но теперь я точно понял , как надо делать. Сейчас быстренько всё перепишу с нуля». Основная проблема заключается в том, что фидбека по фиче ещё не получено, а вы уже начали работать над улучшением кодовой базы. Подобный подход редко приводит к успеху. Не знаю, как у вас, а у меня часто бывает, что после реализации фичи я начинаю понимать, что работать всё должно несколько иначе. И это не из-за того, что я такой глупый, заранее не смог нормально продумать. Просто некоторую функциональность нужно «пощупать», чтобы понять как всё должно быть в релизе. Иногда нужен небольшой прототипчик (пусть даже с говнокодом и багами), чтобы обсудить фичу с коллегами. Иногда нужно что-то показать заказчику, чтобы он мог сказать: «Не, ну я не так хотел, всё должно быть наоборот». Порой пользователями не нравятся нововведения, они хотят всё как было. Проблема новых фич в том, что сложно предсказать их судьбу. Нередко случается так, что все наработки отправляются в помойку, т. к. после обсуждения первой версии коллектив принял решение делать всё иначе. Общий вывод: не стоит рефакторить код слишком рано, особенно если вы не уверены, что этот код 100 % останется в проекте.

Нецелевой рефакторинг

Скорее всего, у вас есть план разработки на ближайшее время. Вполне вероятно, что у вас есть сроки (даже если вы их поставили сами). Релизы нужно делать вовремя, затягивать разработку не стоит. Нужно контролировать себя, нужно заниматься теми вещами, которые входят в ваши непосредственные цели. Допустим, у вас есть кусок кода, который выглядит как полное… Ну, в общем, плохо выглядит. Но, продолжим наше допущение, вы с ним сейчас не работаете. Этот плохой кусок кода стабильно работает, успешно справляется со своими задачами и никак не связан с вашей текущей задачей. Ну так и не трогайте его! Да, вас может крайне печалить то обстоятельство, что на другом конце проекта всё очень плохо . Но заметьте, что прямо сейчас вам это никак не мешает. У вас есть текущие задачи, занимайтесь ими. Конечно, бывают задачи по улучшению кодовой базы, но нечасто - зачастую важнее добавлять новый функционал или фиксить баги. Концентрируйтесь на текущих задачах и не бросайте их из-за того, что где-то там что-то как-то не так.

Рефакторинг ради рефакторинга

Ок, вы пришли к выводу, что нужно обязательно отрефакторить часть проекта. Хорошо, давайте отрефакторим. Вроде бы запланированные улучшения выполнены, но тут возникает мысль: «А что я могу ещё улучшить? Ага, вон ту штуку». А после вон той штуки появится вот эта штука, а потом ещё одна, а потом ещё и т. д. Нужно понимать, что есть плохой код, есть хороший код, есть идеальный код. Последнего в большом проекте у вас никогда не будет. Это не значит, что не нужно к нему стремиться, но нужно понимать его недостижимость. Обычно задача стоит в написании хорошего кода, а не идеального. Допустим, после рефакторинга у вас получился вполне читаемый код, который работает более или менее очевидным образом, в котором нет костылей и которым не так сложно пользоваться. Задайте себе вопрос: «А может, пора остановиться?». Да, код можно улучшать. Причём в достаточно большом проекте его можно улучшать до бесконечности. Но вот прямо сейчас он справляется со своими функциями, им удобно пользоваться, он практически не вызывает у вас дискомфорта. Очень важно определить для себя приемлемое качество кода, после которого вы перестанете его улучшать (до тех пор, пока свойство приемлемости не будет утрачено). Вспомните, что есть ещё так много разных клёвых штук, которые можно дописать. Не нужно рефакторить ради самого рефакторинга, ради идеального кода. Нужно рефакторить, когда у вас есть веские причины на это: код сложно прочитать, код сложно поддерживать, код сложно развивать, код сложно использовать и т. п. Если ни одного «сложно» не возникает, то веских причин тратить время на рефакторинг у вас нет.

Рефакторинг за день до релиза

Бывает так, что релиз послезавтра/завтра/сегодня/должен был быть вчера (нужное подчеркнуть). Это важный момент в жизни проекта. Нужно уделить особое внимание тестированию, фиксам критических багов, финальным доделкам. Поверьте, это действительно плохая идея - перерабатывать кодовую базу (а ещё хуже - качественно перерабатывать) в тот момент, когда нужно отдавать проект в продакшн. Опытная практика подсказывает, что нужно зарелизиться, а потом с чистой совестью спокойно улучшать код. Некоторые спросят: «А почему?». Если такой вопрос возник, то, наверное, вам ещё не приходилось делать сложный рефакторинг. Подскажу: при переписывании код не всегда обязательно улучшается - иногда он может сломаться. Да что там сложный рефакторинг - бывает, поправишь один метод на пять строк, не уследишь за какой-нибудь зависимостью, а на другом конце проекта выползет бага, с которой сразу же встретятся ваши любимые пользователи. Вот вроде бы ничего плохого и не делаешь, а тут внезапно на тебя нападает зверь «Это было неочевидно» и топит тебя в пруду ложной первоначальной оценки. Хотя, может, это просто я такой плохой программист - люблю что-нибудь сломать. Вполне возможно, что вы всегда рефакторите всё абсолютно правильно и с полным контролем всего проекта. В таком случае я могу вас поздравить, но от совета с запретом предрелизного рефакторинга всё-таки не откажусь. Поверьте, за несколько дней рефакторинг никуда не убежит, а сон у всей команды будет чуточку, но спокойней.

Рефакторинг очень старого кода

Вопрос тяжёлый, очень тяжёлый. Ситуация: есть огромное количество ужасных строк кода, которые достались вам от старых разработчиков (возможно, этими старыми разработчиками были вы несколько лет назад, ещё до того, как научились писать всё правильно и сразу). Код приходится поддерживать. То там, то тут возникают костыли и дублирования, энтропия растёт. С каждым днём всё больше хочется выкинуть всё и переписать с нуля. В такой момент нужно очень хорошо подумать о рисках. Да, вполне вероятно, что в перспективе такая деятельность будет полезна. Но в какой именно перспективе и насколько полезна? Скорее всего, в процессе большого рефакторинга или переписывания отдельных частей вы замените старый работающий говнокод новым, идеально написанным кодом, но с багами. И вовсе не из-за того, что вы плохой программист и пишете плохо. Просто вы можете не знать этот код в достаточной мере . Вы можете не знать, почему автор написал всё именно так, а ведь причины могли быть. Иногда приходится писать очень странный и кривой код. Я могу придумать очень много примеров: подавление хитрых оптимизаций процессора, подстройка под баги сторонней библиотеки, подавление каких-нибудь многопоточных косяков и т. д. Я не говорю, что нельзя все эти проблемы решить нормально. Просто иной раз при переписывании казалось бы абсурдного кода на нормальный появляются баги. Да, можно было всё сделать нормально, но вы можете просто не осознать всё величие шалаша из костылей вместо палок, если не узнаете у автора кода, почему он написал именно так (а подобная возможность предоставляется далеко не всегда). Будьте осторожны, когда переписываете старый код, который понимаете не до конца (а особенно, если думаете, что понимать там нечего).

А когда рефакторить-то?

Я прошу прощения, если из этой статьи у вас сложилось впечатление, что от рефакторинга одни проблемы. Я всё ещё настаиваю на том, что код должен быть читаемым и красивым, им должно быть удобно пользоваться, его должно быть легко развивать. Позитивный подход лучше негативного, так что относитесь к рефакторингу не как к источнику проблем, а как к своему очень хорошему другу, который выручит вас в трудную минуту. Более того, этот друг может сделать так, чтобы в вашем светлом будущем трудных минут было бы поменьше. Хотелось бы в завершении обозначить несколько моментов, когда рефакторинг действительно уместен.
  • Нечего делать. Бывают спокойные времена простоя, когда все важные задачи закрыты, а новых пока не поставлено. Ну, не то чтобы совсем нечего делать, но определённое количество свободного времени есть. Потратьте его на улучшение кода. Дайте сущностям понятные имена, избавьтесь от дублирования, перепишите неудачный кусок архитектуры. Хоть нового функционала и не добавляется, но вы вкладываете свою лепту в душевное спокойствие разработчиков, которые будут продолжать проект. Поверьте, это важно.
  • Каждодневные страдания. А бывает так, что есть кусок проекта, который заставляет вас тяжело вздыхать каждый день. А из-за соседних столов слышатся тяжёлые вздохи ваших коллег. Конечно, хоть и релиз и не завтра, но важных задач хватает. Тем не менее, за неделей проходит неделя, а смотреть на этот кусок проекта всё грустнее. Скажите себе: «Хватит это терпеть!». Если бизнес-план составляет начальник, то объясните ему, что этот код просто необходимо переписать. Если работаете на заказчика, то убедите его, что потраченная на рефакторинг неделя позволит сэкономить много времени на разработку в будущем. Если работаете на пользователей, то примите решение о том, что лучше бы этим пользователям в этот раз подождать релиза на недельку больше, но зато потом наслаждаться стабильным ПО и регулярными обновлениями. Да, договориться со всеми и с самим собой не всегда просто, но вы уж постарайтесь.
  • Проблема запоздалого рефакторинга. Не стоит абсолютизировать правило про слишком ранний рефакторинг. Некоторые считают так: «Я вот сейчас наулучшаю чего-нибудь, а оно не пригодится - обидно же будет». Нужно понимать, что в ядре программы вполне могут быть важные части, которым лучше бы быть написанными хорошо. Помните, что чем позже вы проводите рефакторинг - тем выше его цена, ведь вы потратите больше времени и сил на переписывание. Критические базисные вещи (которые используются по всему проекту) должны быть в максимально хорошей форме постоянно. Будет просто прекрасно, если в вашей команде будет работать тезис «Рефакторинг не опаздывает. Он приходит строго тогда, когда считает нужным» .
  • Встреча с монстром. Вы начинаете пилить новый функционал, который должен использовать старый кусок проекта, который выглядит как настоящий монстр: вам становится страшно только при взгляде на внешний интерфейс. Если время позволяет, то поправьте сперва базовую часть кода, чтобы потом сосредоточиться на новом функционале и не отвлекаться на то, чтобы вбить пяток костылей ради повторного использования кода.
  • Разумный перфекционизм. Заметили плохой кусок кода? Хочется его поправить? Очень хочется его поправить? Ну, если прям очень хочется, то можно. Но обратите внимание на слово «разумный». Соотносите время, потраченное на рефакторинг, с выгодой от улучшения кода. Не стоит срывать сроки и зарываться в бесконечные улучшения. Однако если своевременно и в меру заниматься рефакторингом, то проекту от этого станет только лучше.

Вместо заключения

Всё вышеперечисленное является чисто субъективным обобщением опыта работы над рядом проектов. Разумеется, я покрыл далеко не все жизненные ситуации. В каждой команде свои требования к коду, свой бизнес-план и свои правила. Уверен, что у многих найдётся пяток историй из серии «А вот у меня был случай, когда все эти советы не работают». Это абсолютно нормально, так и должно быть. Нет универсальной серебряной пули для определения количества усилий на улучшение кода («Мы будем каждый день 47 минут 23 секунды заниматься рефакторингом - и всё у нас будет хорошо»). Вам нужно исходя из собственного опыта в вашем конкретном проекте, в вашей конкретной команде попытаться найти золотую середину между написанием нового кода и улучшением старого. Я агитирую только за то, чтобы ко всему было рациональное отношение без фанатизма («Зачем улучшать код, нового функционала от этого не появится» / «Нужно срочно весь код сделать идеальным, чтобы потом с ним можно было нормально работать»). Подходите разумно к распределению времени на работу над существующим кодом - и всё у вас будет хорошо.

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