Let’s imagine you want to visit a friend in town but you don’t know where he or she lives, so you call him/her and ask for his/her address. The address becomes your target place, it’s the place where you want to go. When you are about to decide to move, you think, what path should I take so it can lead me to my destiny?…So your options are probably based on less time path, or more secure path, or nearest path. After you decide to use a path, you move and follow it until you end at your destination (your friend’s house).
That kind of thinking is a little bit related with the concept of refactoring. Imagine now that the situation is not to visit a friend but to extract a piece of code in your app. With that piece of code, you want it to live in a new method, the new method now becomes your target (the place where you want to go). So you think again, what path should I take to put that piece of code into a new method in a safe way?…
Wait, safe way?, extract a piece of code can involve a lot of things, you could extract local variables which are used later in the method you extract your code from, code you extracted can also depend on some variables defined before from the code you extract, so this process should be done carefully as current behavior should be preserved.
A refactoring is a prescription of a safe path you need to take in order to solve a particular problem in your code. I like to think about refactoring not as an activity where you remove duplicated code or make your code easier to understand in a deliberate way, a refactoring feels like a guideline, it is a step by step guide to transform your unhandled piece of code into a handled one in a safe way, without affecting code behavior.
Following the example I mentioned earlier, supposed that the code I want to extract is related to outstanding calculation:
which path should I take? how should I extract that code? well, there is a refactoring called Extract method with the mechanics(path) to extract a piece of code into a method in a safe way. I use this refactoring almost every day and it has became pretty natural to me to apply. After applying Extract Method Refactoring my code looks like this:
Look that code I extracted depends on customer variable. customer is just used to read some of its attributes (orders), so I passed it as a parameter to the function calculateOutstanding. However, outstanding variable is calculated and then it is used later in print details section inside printFor function, that’s the reason why it’s returned.
Extract method is just one of many refactorings existing. Every refactoring has a template, if you click on Extract Method link mentioned before, you’ll see the first thing is a definition about that refactoring, and coming next you’ll see a before and after refactoring class diagrams, which means “go from this start point to this target point”, there is also a motivation to use the refactoring, mechanics(path or step by step) for applying it and some examples.
Nature is full of balance and contrast…
There is no existence of light if darkness would not exist, we would not talk about war if we don’t know what peace means, we inhale oxygen produced by plants to exhale carbon dioxide which feeds plants. So, we can not mention refactoring without talking about code smells. Refactoring would not exist if code smells do not emerge.
In a simple way, code smells are those “things” that make you feel like there is something wrong in your code. When emerging, they can make your code hard to change or understand. Some of us recognized duplicated code introduced in an application. Duplicated code is considered as a code smell because of the impact it can cause when changes need to be done. You will need to introduce the changes as many times as the code is duplicated. Here is a list of some code smells you can probably deal with:
Duplicated Code
Long Method
Large Class
Long Parameter List
Divergent Change
Shotgun Surgery
Feature Envy
Data Clumps
Primitive Obsession
Switch Statements
Parallel Inheritance Hierarchies
Lazy Class
Speculative Generality
Temporary Field
Message Chains
Middle Man
Inappropriate Intimacy
Alternative Classes with Different Interfaces
Incomplete Library Class
Data Class
Refused Bequest
Code smells are out of scope for this post, I’ll talk about them in another entry, I think they are as important as refactoring. What I really want you to know is that refactorings help to mitigate a code smell, when a code smell is detected, there is at least one refactoring technique to make it disappear.
Refactorings can be applied in an incremental approach. You start applying one small refactoring in a method, then a medium one in a class or object and after that you can apply a bigger one between two classes or components. This is an approach used in emergent design, the result for this process is to accomplish a more robust design which can suit to a pattern design. I recommend you take a look to Refactoring to Patterns by Josh Kerievsky.
To conclude, refactoring (the verb) is an activity we as developers must consider to practice and learn more about it. Code smells are inherent attributes when developing software, they always seem to appear, learn to detect them and mitigate them using refactoring techniques require some practices and discipline, but the result is a code that looks cleaner, easy to change, easy to mantain and easy to extend.
Keep learning, keep applying.