Автоматизация рефакторинга JavaScript

Рефакторинг? Это нецензурное слово?

Я часто слышу (и говорю): «Нам нужно это реорганизовать!» и это то, что воспринимается с подозрением.

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

Итак, что такое рефакторинг?

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

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

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

Код-мод, что это?

Код-мод пишет код для преобразования кода в новый код. Чего ждать?

Хорошо, давайте начнем с маленьких шагов ... Если вы еще не слышали о JavaScript AST, вам лучше освежиться!

С помощью AST вы можете представить свой код в виде древовидной структуры, но за кулисами это JSON. И мы можем легко манипулировать JSON!

Уже есть коллекции кодовых модов, которые вы можете запускать в своем коде, например js-codemod и response-codemod, но вы можете написать свои собственные: Facebook создал для этого инструмент: jscodeshift.

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

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

Предположим, что некоторые из ваших коллег (это, конечно, никогда не бывает!) Написали неэтический кодекс, и вы хотите его реорганизовать.

const destroyBaghdad = () => {
  // code here
}
// used as:
destroyBaghdad();

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

export default function transformer(file, api) {
const j = api.jscodeshift;
return j(file.source)
       .find(j.Identifier, {name:'destroyBaghdad'})
       .forEach(path => {
         j(path).replaceWith(j.identifier('destroyCity'));
         if (path.parentPath.value.type === "CallExpression") {
           path.parentPath.value.arguments =                   
                                           [j.literal("Baghdad")];
         }
       }).toSource();
}

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

const destroyCity = (city) => {
  // code here
}
// used as:
destroyCity('Baghdad');

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

Если вы заинтересованы в написании кода-модов, почему бы вам не присоединиться к нам?