A whole post about getting to the refactoring; what nonsense... Wait... I did that... >.<
First thing you gotta ask yourself when refactoring is, "Do I feel lucky?" Well... Do ya? 'Cause if you're feeling lucky; don't worry about unit tests. If you know what you're doing - We need tests.
before starting any kind of major refactor there needs to be test to ensure we're not breaking functionality.
FyzLog
has tests, they're available in the gist. Now that we have passing tests (trust me...) we can begin the refactor.
I'll note here; I've done this refactor before. I'm redoing it as I'm writing this; but I have an idea where I'm going already. It might show in a few places.
Looking at the pattern of the log level methods
We can see that there are two very distinct behaviors happening here; System.out
and android.util.Log
.
Since it's the 'odd case' in the logger, I'll extract the println
behavior first.
During this refactor; I'll be dropping the comments as I perform refactorings. Comments are a smell as they go bad real quick. Most of these comments were originally put in to explain the purpose of each method - Very explicitly a code smell[1].
We're going to perform an Extract Class[1:1] refactor on the println
method. This and all dependent methods will be moved into a separate Logger
class.
This doesn't compile yet as the extracted class has an unknown variable on lines 15 and 40. We need to refactor println
and log
with Add Parameter[1:2] to have access to this.
We've done a chunk of refactoring; Run the tests. ... They still pass... Yes, DUH - We haven't changed the FyzLog, but tests need to be run after each compiling step.
The println
method's visibility was private, we'll need to refactor the visibility so it's available in FyzLog
.
The Logger
class is a class for just FyzLog
to use, so let's restrict it's visibility to package-protected
Run Tests
Now we can refactor the wtf
method to call Logger.println
; which will require passing in the added parameter.
Run Tests
Apply this refactor to the rest of the log level methods.
Run Tests
Static methods are a bit of a code smell[1:3]; let's refactor Logger
into an instantiated class.
The only change to Logger
is removing the static
modifier from println
Then we're able to update FyzLog
to instantiate
Run Tests
This refactor is applied to each log method; creating a new object EVERY LOG!!! I'm against premature optimization[1:4], but this isn't premature. We have a stateless object. This is, what should be, a rare case where we need to Limit Instantiation with Singleton[1:5].
And make FyzLog
compile using this refactoring
Run Tests
Looking through FyzLog
our IDE (in this case, AndroidStudio) helpfully highlights FyzLog#println
as unreferenced. Let's perform some cleanup on FyzLog
as finalization of our earlier Logger
Extract Class refactor.
Delete FyzLog#println
.
Run Tests
This cleanup also exposed FyzLog#getLevelTag
as only being called from FyzLog#println
and it can be deleted.
Run Tests
Deleting code; such a great feeling.
This is a pretty good break point for the post. We've gone through and performed, basically, an Extract Class to pull out some related functionality for one of the branches in our logging methods.
You can see the state of FyzLog
here.
I see that this post is pretty short via word-count; around 500 words (depending on how much I ramble here) and for a refactor - That's fantastic. Each step should be small. Let's keep the posts on this refactor following that "small step" model.
Next up: Extract Class of the Android Log functionality!
Part 1 - [Part 2] - Part 3 - Part 4 - Part 5