Introduction
This blog post will show, using videos, how to perform basic refactorings in IntelliJ. I’m using the IntelliJ 2020 community edition and OBS Studio to create these videos.
The philosophy contained in these articles will largely be drawing from my favorite book on refactoring: Refactoring: Improving the Design of Existing Code by Martin Fowler.
Prerequisite: Test Coverage
There should exist (or you should write) comprehensive test coverage on all code within the scope of our refactor. This is to help ensure that nothing, functionally, is changed during refactoring.
If you need help getting test coverage on your legacy code, check out my other blog articles such as Suppressing Static Initializers with Mockito + Powermock.
Identifying the Need for Extract Method
A common pattern for junior developers is to place a lot of code in a single method, but logically break it up with comments and log statements. This tells us that there is one method responsible for multiple operations (not ideal) and alerts us that the class should probably be refactored.
Here we have a simplified example, Demo.java
import java.util.Map;
public class Demo {
public String getFirstName(String domain, String username){
// step 1, generate connection string
System.out.println("Generating connection string");
String connectionString = Constants.BASE_DB_URL + domain;
// step 2, get mapping of usernames to first names
DbQueryDummy dbQueryDummy = new DbQueryDummy(connectionString);
Map<String, String> dbUsernameToFirstName = dbQueryDummy.getDbUsernameToFirstNameMap();
return dbUsernameToFirstName.get(username);
}
}
Refactored Version
With two extract method operations, and three inline variable operations, we can refactor this code to the following:
public class Demo {
public String getFirstName(String domain, String username){
return getFirstNameFromDB(username, getConnectionString(domain));
}
private String getFirstNameFromDB(String username, String connectionString) {
return new DbQueryDummy(connectionString).getDbUsernameToFirstNameMap().get(username);
}
private String getConnectionString(String domain) {
System.out.println("Generating connection string");
return Constants.BASE_DB_URL + domain;
}
}
In my opinion, this refactored code is better because we’ve:
- Eliminated the temporary variables
- Split the getFirstName method into two logically discrete parts
- Alleviated the need for explaining comments; We have nicely named methods instead
If this was real world code, I’d love to refactor DbQueryDummy to remove the chained method call in our getFirstNameFromDB method, but that’s not important for the purposes of this article.
Behind the Magic: IntelliJ Refactoring Tools
To perform similar refactorings: I highly recommend becoming familiar with IntelliJ’s code refactoring tools.
Refactoring in your IDE does help eliminate silly mistakes, but it isn’t perfect. Using an IDE doesn’t negate the need for comprehensive testing around the code being refactored.