(clipped) “… this is the perfect time to refactor this puppy and make it more portable, reusable, reliable, easier to configure etc. Now that’s fine and dandy, but then I started feeling a tad overwhelmed regarding to where to start. Should it be a separate library? How should it be configured? Should it use IoC? DI?
So my [admittedly subjective] question is this — given a relatively small, but quite useful class like the one below, what is a good approach to refactoring it? What questions do you ask and how do you decide what to implement or not implement? Where do you draw the line regarding configuration flexibility?
[Note: Please don’t bash this code too much okay? It was written a long time ago and has functioned perfectly well baked into an in house application.]”
Before we get into the code sample, let’s address some of the key questions…
“What is a good approach to refactoring it? What questions do you ask…?”
The first question I would ask is:
1. Do I need to refactor this code at all?
In this case, the author commented at the end of his question that the code “was written a long time ago and has functioned perfectly well baked into an in house application”. This comment suggests there may not be a need to refactor at all! If the code has survived and hasn’t been modified in a long time, it probably doesn’t make sense to change it now. However, let’s assume we have good reasons to start (e.g. need to start making a changes)…
2. What is my objective in refactoring the code?
The term “refactoring” is becoming quite commonplace, and it is often used interchangeably with any type of code modification. However, in Refactoring: Improving the Design of Existing Code, Fowler defined it as
“Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.”
With this definition, Fowler highlights that refactoring is not any general modification to the code, but specifically a change with the intention to “make it easier to understand”.
“You are constantly mercilessly refactoring systems,
not necessarily because they need to be refactored
but because they need to remain flexible. So it’s
rather like moving the gears on a bicycle or driving
your car for no other reason than to keep it well
lubricated, and in order to make those kinds of
changes you need tests, it all boils down to tests in
(Before we move on, I want to highlight another important fact. You cannot be sure you haven’t changed behavior unless the code is covered by good unit tests. So, without good unit tests, you are not really refactoring.)
With this context in mind, we can determine how to make the code more flexible, easier to understand, and cheaper to modify.
3. What should I do? What should I refactor?
The reason I was attracted to this particular code sample to highlight is that it is actually a fairly decent piece of code. I can see, as the author points out, that it could have been good enough to support an existing application without many problems. I also think this sample is reflective of the type of code I generally see in the wild: functional, but not expressive.
Additionally, even for a small code sample, it contains quite a bit of code duplication. I feel this amount of duplication is typical (unfortunately) of the average application.
The biggest step you can make to improve your code is learning (1) how to remove duplication, and (2) how to make your code more expressive.