In the previous post I wrote about using Clojure zippers to refactor code. That's been a handy tool to have in my toolbox because while IDEs can often refactor code, they're generally constrained to language-specific patterns or text-based custom transformations. Teams, projects, and libraries, however, can have their own idioms that are hard to encode in an IDE or auto-formatter. Here are a few times I've written custom refactors using zippers.
if
statements to ternary expressionsBranches of if
statements tend to accumulate code, so whenever an if
looks like this:
let variable;
if (condition) {
variable = some_value;
} else {
variable = some_other_value;
}
I like to nip the branches in the bud to avoid more complex, even branchier code, so I'll often turn statements like the above into an equivalent ternary:
const variable = condition ? some_value : some_other_value
That's a language-specific transformation, but teams I've worked on have had preferences on how to format that syntax (split clauses onto separate lines?) and how far to go with it (include else if
branches as nested ternaries?), details that could possibly be provided by a combination of generic refactoring and auto-formatter, though I don't recall finding any at the time.
One library-specific refactor I've written turned React function components into class components, in order to add lifecycle methods (this was before the introduction of React hooks). The refactoring logic didn't do much, just found the full body of the function and wrapped it in a render
method of a class. It might also have saved the constructor's props
argument as an instance attribute.
One team I worked on used Ramda heavily, and I wrote refactors to transform basic JavaScript property access to use Ramda's prop
, propOr
, path
, and pathOr
functions, as well as to turn calls like R.map(x, y)
into the start of a functionally composed pipeline of the form R.pipe(R.map(x))(y)
.
In an earlier post I mentioned refactoring Java and Kotlin annotations, which I did as part of an upgrade of Swagger to OpenAPI 3. Rewriting the annotations involved more than just swapping a few annotation names. Fields on the annotations also needed to be renamed, and long string values had to be re-line-wrapped.
If you have suggestions for how to manage team-, library-, and project-specific refactoring needs, please email me.