Let’s talk about refactoring again: How can you move some code to different value objects using small, safe steps? In this video, I want to show you exactly which refactoring steps I take to extract a factory method, move it to one value object and move some code around it to another value object.
In my last video about “Refactoring Primitive Obsession”, I did all that very quickly to give you an overview about the whole process. I have added a link to that video in the description.
Today I want to show you a small step from this process and explain exactly what I did.
Intro (TL;DR)
My name is David and I am a trainer and technical agile coach with over 12 years of experience. In my videos, I want to show you techiques and tricks that I use and that I also teach when training or coaching teams.
Today I want to try something new: A very short video that focuses on a single thing. In this case, one refactoring step.
By the way, if you like this video, please subscribe to my channel and share it with your friends and followers - That would be awesome!
Question / Problem
In the code I want to start with, I already created a type for TaxAccountNumber
but it does not do anything yet. It only wraps a single string.
TaxAccountNumber taxAccountNo = TaxAccountNumber
.fromString(taxAccountNoUnvalidatedUserInput);
String taxOfficeIdInput = taxAccountNo.asString().substring(0, 2);
Integer taxOfficeId = Integer.valueOf(taxOfficeIdInput);
Now, I want to create a new type for the taxOfficeId
, complete with a factory method, and move the code for extracting the first two digits and creating the taxOfficeId
to TaxAccountNumber
.
Solution
First, I create a class TaxOfficeId
that wraps the taxOfficeId
integer. I create a new variable, taxOfficeIdObject
, for it and replace all usages of the integer with the new object.
TaxAccountNumber taxAccountNo = TaxAccountNumber
.fromString(taxAccountNoUnvalidatedUserInput);
String taxOfficeIdInput = taxAccountNo.asString().substring(0, 2);
Integer taxOfficeId = Integer.valueOf(taxOfficeIdInput);
TaxOfficeId taxOfficeIdObject = new TaxOfficeId(taxOfficeId);
TaxOffice taxOffice = taxOfficeRepository.findByNumber(taxOfficeIdObject.asInteger());
if(taxOffice == null) {
payTaxesView.showTaxOfficeError(
"The tax office \""+taxOfficeIdObject.asString()+"\" does not exist.");
} else {
//...
}
I can extract the two lines that convert the ID string to an integer and create the object to a new method on the controller class, named fromString
. When I make this method static, I can then move it to the class TaxOfficeId
.
TaxAccountNumber taxAccountNo = TaxAccountNumber
.fromString(taxAccountNoUnvalidatedUserInput);
String taxOfficeIdInput = taxAccountNo.asString().substring(0, 2);
TaxOfficeId taxOfficeIdObject = TaxOfficeId.fromString(taxOfficeIdInput);
As a last step, I can now extract the two lines that get the sub-string and create the tax office ID to another method and move it to the class TaxAccountNumber
. So, I first extract a method from the two lines, then I move it and last I inline the redundant call to asString
in the moved method.
I can also rename taxOfficeIdObject
to taxOfficeId
again, because there now is no name clash anymore.
TaxAccountNumber taxAccountNo = TaxAccountNumber
.fromString(taxAccountNoUnvalidatedUserInput);
TaxOfficeId taxOfficeId = taxAccountNo.getTaxOfficeId();
Conclusion
The tax office ID is a part of the tax account number (encoded in the first two digits), so it makes sense to have the code to extract and create it on the class TaxAccountNumber
.
The code I created with this refactoring now reflects the domain concept of a tax account number much better than the old version.
I was either adding code or using built-in IDE functionalty to transform existing code. Both operations are reasonably safe. And I ran the tests after every step. This allowed me to change the code and be very sure that I did not change any functionality.
CTA
What do you think? How would you refactor this code? Please tell me in the comments on youtube or on Twitter, where I am called @dtanzer.
And if you liked this video, please subscribe and share it with your friends and followers (using the share buttons below) - That would be awesome!