Эффективный рефакторинг: часть 4

Переписывая код

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

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

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

Определите возможности для автоматизации

Есть очень вероятность того, что у вас будут утомительные задачи по проекту. Одной из самых серьезных проблем, с которыми я столкнулся, было перемещение файлов. Например, приложение, которое я реорганизовал, имело действия, редукторы и селекторы Redux в их собственных отдельных папках. Одна из задач моего проекта заключалась в том, чтобы сгруппировать файлы Redux по модулям (например, appActions.js, appReducer.js и appSelectors.js). Я мог бы запустить команду git mv, чтобы переместить /actions/app.js в /redux/app/appActions.js, а затем сделать то же самое для /reducers/app.js и /selectors/app.js, но это касается только модуля приложения. В этом проекте было 11 модулей, поэтому мне пришлось набрать 33 git mv команды только для элементов Redux. Возможно, вам придется запустить git mv еще 150 раз, чтобы получить контейнеры и компоненты React в нужном месте папки!

Вы обнаружите, что эта ситуация может быстро стать неприемлемой. Вместо того, чтобы вводить все эти команды, я написал сценарий, который сделает это за меня, используя JavaScript и Node.js:

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

Часто фиксировать

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

  • 1,747 совершает
  • 378 закрытых запросов на вытягивание
  • 42 017 строк текста в файлах снимков 169 Jest
  • 13 555 строк текста в 181 тестовых файлах
  • 24 261 всего строк текста в 2 файлах фиксации (responses.js и state.js)
  • 16685 строк текста в файлах 198 JavaScript
  • 3 823 строк текста в файлах 111 Sass

Это 76 080 строк кода в файлах 659, а размер репозитория составляет всего 10 МБ. Делайте все, что хотите - git справится с этим. Вы всегда можете раздавить их позже, если хотите навести порядок в своей истории. Я призываю вас делать это как можно чаще; при рефакторинге большого приложения вы очень быстро поймете, насколько сложно может быть отслеживание мелких, критических проблем.

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

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

Избегайте искушения

Избегайте стремления очистить код, выходящий за рамки текущей задачи. Это один из самых сложных аспектов рефакторинга. Допустим, вы работали над задачей под названием "Стандартизация имен селекторов Redux" , которая включала обновление имен селекторов, чтобы все они были добавлены к слову select. Поскольку это относительно простая задача с низким уровнем риска и четко определенным объемом, она должна выполняться гладко; вам просто нужно обновить имена селекторов (вместе с любыми файлами, которые ссылаются на эти селекторы), чтобы учесть изменения (и не забывайте о тестах!)

Допустим, вы столкнулись с селектором, который использует Object.assign(), и одна из ваших будущих задач - обновить код, чтобы использовать некоторые из новых функций ESNext, таких как синтаксис распространения. У вас может возникнуть соблазн обновить этот код, но не делайте этого!

Крайне важно не отклоняться от текущей задачи. Даже самое тривиальное изменение может направить вас по ложному пути. Несмотря на то, что концепция скользкого пути является логическим заблуждением, часто возникает менее гиперболическая ситуация. Вы начинаете изменять Object.assign() операторы, и, прежде чем вы это осознаете, прошло 4 часа, а вы обновили только 2 названия селекторов!

По мере того, как я выполнял свои задачи по рефакторингу, я становился менее восприимчивым к такому типу поведения. Я добавил // REFACTOR: Fix this later комментарий в код и проверил свой проект, чтобы убедиться, что у меня есть задача по внесению изменений, затем я двинулся дальше.

Будьте методичны с запросами на слияние

Pull-запросы - отличный инструмент для рефакторинга проектов по ряду причин, они:

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

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

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

Одна метрика, о которой вам нужно знать, - это количество изменений, связанных с запросом на вытягивание. Постарайтесь ограничить количество изменений до +/- 500 строк кода. Добавление файлов моментальных снимков Jest может легко добавить тысячи строк в запрос на перенос, поэтому обязательно включите примечание об этом в сводку. Если вы не можете свести к минимуму количество изменений, постарайтесь уменьшить сложность. Если вы просто переупорядочиваете операторы импорта, допускается превышение 2000 строк кода при условии, что изменения не слишком сложны. Постарайтесь выделить это изменение в единственном PR и убедитесь, что вы описали природу изменения в резюме. В начале резюме полезно выделить жирным шрифтом пометку вроде «Никаких изменений в логике не было» , чтобы у рецензента был правильный контекст.

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

Заворачивать

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

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

  • 40 задач выполнено
  • 12 ожидающих задач
  • 1 Зарегистрирована ошибка Jira (напрямую связана с рефакторингом)
  • 1473 тестов, написанных для 181 набора тестов (737 из которых были тестами снимков)
  • Добавлено 108 450 строк и удалено 44 241 строк.
  • 38 запросов на вытягивание
  • 99,84% Покрытие заявления
  • 95,07% Покрытие филиалов

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