Refactoring tools and their underlying algorithms have come a long way and are reasonably battle-tested. However, there may be a situation that you run into where the automated refactoring action cannot complete the intended transformation. In such scenarios, a little nudge from the type system can get you over the bump.
Here is one such example,
The code snippet above shows a when
block that contains code we want to extract to a new function.
However, after using the 'Extract Method…' refactoring action, the extracted when
block inside the
new getDuration
function has a compilation error.
Let's take a moment to understand what happened. The key to remediating this situation lies in lines 505 and 506.
From the snippet above, we know that the storyPost.content
type can be either TextContent
or AttachmentContent
.
After performing the suitable type checks, we call the desired methods on the content
object.
It also means that TextContent
and AttachmentContent
have at least one ancestral type in common.
But, if you pay attention to the second parameter type in the extracted getDuration
function, it is marked
as TextContent
. This type mismatch is what has caused the compilation error on line 506.
The 'Extract Method…' refactoring algorithm used the type information from line 505 for the second parameter. If the algorithm also considered the type information from line 506, it would have used the ancestral type and completed a clean extraction.
Providing type information for remediation
Since the extraction did not go through, we will discard all the changes and try a different approach. We know the 'Extract Method…' algorithm needs the information of the ancestral type. If we can somehow provide this information to the algorithm, it should be able to make a safe transformation.
'Introduce Variable…' to the rescue
Let's add an intermediate transformation before we try to extract the function again. We'll first select
the storyPost.content
expression (line 427) and extract it as a new variable.
The newly introduced content
variable (line 424) has the common ancestral type StoryPost.Content
. This additional type
information should help the 'Extract Method…' algorithm.
Now, try selecting the when
block again and perform the 'Extract Method…' action.
This time, the extraction was completed cleanly without any problems.
Look at the second parameter type in the extracted getDuration
function. In this case, you'll also notice that the
'Extract Method…' algorithm has picked the right type after the 'Introduce Variable…' refactoring.
Conclusion
While modern refactoring tools are powerful and often reliable, they may still encounter scenarios where they fail to make the intended transformation. In such instances, understanding the underlying problem is crucial. As demonstrated in this example, by introducing an intermediate transformation, we provided the tool with the necessary type information, enabling a clean extract method transformation.
This example highlights the importance of a deep understanding of the code and the tools at one's disposal. Sometimes, a slight modification or a gentle push in the right direction can make all the difference in achieving the desired outcome.
Want more insights like this? Dive deeper into working with legacy code with our articles on best practices, tips, and tricks. Subscribe to our blog and stay updated!