We present reCode: A Lightweight Find-and-Replace Interaction in the IDE for Transforming Code by Example
I’m Nimo, PhD student from Carnegie Mellon University. This is joint work with colleagues at Microsoft
Say we’re replacing the name of a function. For one line of code, just select and type. Easy
Multiple lines? Gets a little tedious, so we’ll use find and replace
Oh, be careful about not replacing the comment
We could also use the rename refactoring in the IDE
In this case, we’re consolidating two function calls into one.
The code calls expect with “a”, and then “toEqual” with “b”.
We want to change it to a single call to “same”, with both “a” and “b” as arguments.
For multiple lines, there’s no refactoring tool for this kind of change
and find and replace won’t get us very far, because every line is slightly different.
These four lines only share common keywords like "expect" and "toEqual"
but our change involves moving the arguments around.
So we are doing it manually instead
Just like what we did
developers frequently perform repeated systematic code transformations on similar but not identical code
to refactor their code base, migrate to a new API, adopt new coding style guidelines, and so on
These code transformations can frequently be repetitive, and sometimes edit thousands of files
When there are only a few lines to transform, it doesn’t take much time to do them manually
When there are hundreds or thousands of files, though
writing a robust code transformer which can take hours, is worth the investment
How about something in between, say, 50 changes across 10 files?
Manually making the changes is both time consuming and error prone.
We could use macros, multi-cursor mode, or regexes, but which one to choose?
This is the "murky middle" that developers frequently find themselves in
where light-weight automation can provide a lot of benefit.
In this murky middle, there are a lot of tools to choose from, but which one applies to our situation?
And which is worth the uncertain time investment?
In short, developers face a decision paralysis and often default to manual editing instead
In our formative interviews, participants expressed desires to make code transformations by editing files directly
and have the editor apply it elsewhere automatically.
Let’s revisit our example
What if we can make one change to any line that needs to be transformed
But this time the editor knows what we want to do
and intelligently suggests edits to us?
Instead of a macro that just repeats our actions naively
the editor actually understands the code transformation at the language level
and performs an appropriate edit to each line
This is what reCode does. Let’s look at the way a developer uses reCode in detail:
In this scenario, the developer wants to upgrade from
JavaScript ES5 to ES6 for their React website
One new feature in ES6 is arrow function
The old code in the site have these “bind” calls in the constructor
The goal is to remove it, and change the corresponding member function below to an arrow function
To initiate the interaction, the developer first finds potential locations to change
The search term does not need to be precise, as long as it gets them to all lines of interest.
In this case, the developer types “bind”
“Find” is a natural entry point to reCode, because developers already do this every day:
they frequently search for short keywords in “Find” as a way to navigate the code base
For reCode, the find result communicates a rough scope of code transformation
For the developers, it’s a workspace for bookkeeping and planning
After clicking on a keyword match in the result view, the developer then directly makes a change in the main editor
Deleting the bind call for “changeTab” and changing “changeTab” below to an arrow function
Notice that this change goes beyond the line with the keyword match and span multiple lines in the current file
reCode treats the edits to both lines as one positive example of code transformation
And generalizes it to other matches in the “Find” result
Internally, reCode synthesizes a program for this transformation
which performs the change generally at the abstract syntax tree level
Once the transformation is synthesized, suggestions are displayed in the result view as yellow highlights
and inline as diffs and code lens
The developer can accept or reject one or multiple suggestions
This process is iterative, because reCode continues to run in the background as the developer interacts with the suggestions
reCode treats each accepted suggestion as an additional positive example, and each rejected suggestion as a negative example
The process continues iteratively until the developer closes the “Find” view
We performed a usability evaluation of reCode
and found that developers successfully completed tasks ranging from simple renaming to complex multi-line changes
In under 5 minutes on average
In the followup interviews and survey, participants commented positively about their experience with reCode
The tasks appear frequently in their daily work and are tedious to perform manually without reCode
All of them indicated that they would use a production version of reCode
Code transformation is a deliberate activity.
Participants appreciated the more active interaction model of reCode
as compared to the more passive model of, say, autocompletion.
They also commented positively on how reCode fits easily in their workflow of code editing.
For in-depth discussion on related work, how the synthesis engine works, and more, check out our paper!
Email or tweet at me to get in touch!
Thanks for your attention!