Developers often create long methods when a project has been in the works for some time without a clear idea of how it will be structured or if later features will be added. These methods can be hard to maintain and debug, and it is often easier to break them up into smaller classes or methods with a clear purpose.
One of the solutions to eliminate the long method is to replace it with the Method Object.
Method Object is a class you create to put the logic of the long and messy method. By applying this refactoring, you will make it easier to maintain and debug the code.
In this post, I will show you how to use Replace Method with Method Object refactoring in C# and show how your code can benefit from this refactoring.
Why and when should you use the method object refactoring?
When you work on an existing project, you don’t always have the option to use short and simple methods. For example, sometimes a method explodes in size. Usually, the easiest refactoring to perform is the Extract Method. With Extract Method refactoring, you can refactor a long method into shorter, simpler methods, making the code easier to read, maintain, and less error-prone.
However, on some methods is not easy to use the Extract Method refactoring. This is a case when the method has many parameters, many local variables, and it uses variables and parameters in a way that it’s not simple to extract small chunks. In those cases, you can use the Replace Method with Method Object refactoring. This refactoring involves moving the existing method into a new class. The code of the original method is copied into a new method inside the new class, and you call that method from the existing code.
How to use Replace Method with Method Object refactoring technique?
To perform this refactoring, you need to follow the next steps:
- Create a new empty class and name it based on the purpose of the method.
- [OPTIONAL] In the new class, create a private field for storing the original class. There is a possibility that you will need to call some methods from the original class.
- Create a private field for each local variable.
- Create a constructor that takes the same parameters as your private method.
- Create a new public instance method, copy the body of the original method to it, and replace the local variables with the private fields of your new class.
- Create a new class instance, and call the main method in the original class.
Of course, before applying this (or any other refactoring), you should have tests around the existing functionality.
Example
We have the following GetEditId private static method.
private static async Task<string> GetEditId(string appId)
{
var response =
await new HttpClient()
.PostAsync($"https://www.googleapis.com/androidpublisher/v3/applications/{appId}/edits", null);
var responseString = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
var error = JsonConvert.DeserializeObject<GoogleError>(responseString).error;
throw new InvalidDataException(error);
}
var editId = JsonConvert.DeserializeObject<Edit>(responseString).Id;
if (editId == null)
throw new InvalidOperationException("Failed to create new edit");
return editId;
}
The method starts by making an HTTP request to the Google API to get the application edit. If the request is unsuccessful, the code uses JsonConvert to get the GoogleError and throws an exception.
On the other hand, if the result is successful, the code gets and returns the value of the editId. The method is not too complicated, but it will be the target of the refactor in this case.
You start by creating a new class. Name it ApplicationEdits.
public class ApplicationEdits
{
}
You can skip the second, optional step to define a private field for storing the original class. The method doesn’t use any member of the original class.
The next step is to create the private field for each local variable.
public class ApplicationEdits
{
private HttpResponseMessage _response;
private string _error;
private string _editId;
}
Next, create a constructor with the appId parameter.
public ApplicationEdits(string appId)
{
_appId = appId;
}
Now you can define a new method and copy the code to it, use the fields from the new class.
public async Task<string> GetLatestEditId()
{
var _response =
await new HttpClient()
.PostAsync($"https://www.googleapis.com/androidpublisher/v3/applications/{appId}/edits", null);
var responseString = await _response.Content.ReadAsStringAsync();
if (!_response.IsSuccessStatusCode)
{
_error = JsonConvert.DeserializeObject<GoogleError>(responseString).error;
throw new InvalidDataException(_error);
}
_editId = JsonConvert.DeserializeObject<Edit>(responseString).Id;
if (_editId == null)
throw new InvalidOperationException("Failed to create new edit");
return _editId;
}
And voila, you have a new class you can test or further modify. The last step is to call it from the parent class.
Advantages
Method object refactoring is a great way to clean up your code and make it more readable. The main advantages are:
- Improved code structure – once you create a new class out of your method, it will be easier to read and understand the code.
- Easier testability – once you have the method inside the new class, it will be easier to write tests for that method. In some cases, the original method had a private modifier, and maybe it wasn’t possible to cover all edge cases. With the new code, increasing code coverage will be much easier.
- Easier modification – once you have your method extracted in a brand new class, it will be easier to add new features to it. It will also be easier to split the method into smaller methods inside the new class.
Disadvantages
While the usage of method object brings a lot of advantages to the developer, it has a few disadvantages. First, you need to create and maintain yet another class. This might add some complexity to the code. The other disadvantage is that this refactoring can cause bugs if you don’t follow the exact steps. Or if you don’t have any tests as a safety net.
Conclusion
In this post, you have learned how to simplify your code using the Replace Method with Method Object refactoring. The original method is extracted into a new class, and then all the previous code is wrapped inside the new class. In the refactored code, you can use other refactorings to further simplify the code.
Which is nice.
Since we need more simple code in this world.