Android Logger Refactor - Objectify

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



  1. [RP p296] Limit Instantiation with Singleton ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎