Tuesday, December 15, 2009

Learning how to refactor

Refactoring is the process of improving the design and the flow of existing, working code by applying common patterns, like extracting a superclass or a method, or even introducing new classes as well as deleting existing ones.
Probably if you are here you have already experienced the refactoring process, but I want to clarify the common iterative method I use, to get feedback and being helpful to developers who are naive in this practice.

This is the general process to learn how to refactor code, which wraps the basic refactoring cycle.
Step 1: get the book Refactoring: Improving the Design of Existing Code by Martin Fowler (a classic) or a refactoring catalogue on Wikipedia or Fowler's website. In the book or in a similar guide, there are two lists which are very boring if read sequentially: smells and refactorings. Smells are situations that arise in an architecture, while refactorings are the standard solutions to eliminate smells. It is annoying to keep something that smells in your office.
Since it is very boring to read the Refactoring book if you have even a small experience with the practice, the best way to extract all Fowler's knowledge is to apply it directly.
Step 2: For S in 'smells':
  • Read about S; understand what is the problem behind a practice that you may have used without worries.
  • Loof for S in one of your personal projects or where you have commit access and responsibility for the code base; get convinced that this smell should be eliminated. If you are not convinced, stop here this iteration and go to the next smell; your existing solution can be pragmatically correct in the context of your style or in your architecture. Note that there are no absolute reference points and refactorings often come in pairs: it is up to you to choose if refactor in a direction or in the opposite one (Extract Method or Inline Method?)
  • Find an appropriate refactoring R; there are multiple solutions that can eliminate a smell. Be consistent in your choice in different places.
  • Make sure there are unit tests for the code you're going to edit. No further action should be taken before you are sure functionality is preserved. This is the answer to the question "Why change something that works?"... Because it will still work, but much better.
  • Apply R in small steps, running focused tests every time to ensure you have not break anything.
  • Once the refactoring is complete, run the entire test suite to find out if anything is not working. Note that failures in points distant from refactored code constitute a smell too: they are a symptom of coupling.
  • svn diff will calculate a picture of your modifications; ensure that debug statements or workarounds are not in place anymore.
  • svn commit (or git equivalent commands) pushes your improvements to the repository. Using version control is also fundamental in case you get in a not recoverable state: svn revert -R . is the time machine button (no, Apple has nothing to do with it) to restore the original code.
The goal of learning various refactoring techniques is to easily see smells in the future, to improve the efficiency of the Refactor phase in the Red-Green-Refactor cycle. Your bricks (classes) are very malleable when fresh, but when they solidifiy it becomes harder to add further modifications: it is good to refactor as much as possible just as you have finished adding code for functional purposes.


Nikolaos Dimopoulos said...

Great post. I was thinking of posting something similar in my blog too.

Although this book's examples are in Java, it takes very little for the reader to understand the underlying technology and methodology that Martin Fowler follows.

Equally easy is the application of the methodology to one's projects once this book is read.

Great read and thank you Giorgio for the post.

Fedyashev Nikita said...

You've mentioned a great book on the topic. It contains a great amount of different refactorings.

But one problem that I have with it - is that you forgot about some refactorings which can be rarely applied but still very effective.

How this problem can be solved? What do you think?

Giorgio said...

I forgot or the book forgot? The suggestion of working on a personal project is to have a large codebase where many refactoring techniques will apply.

Anonymous said...

Hi Giorgio, do you have any plans to add a feed for the comments? I would find that useful, as I find the comments interesting also.

Giorgio said...

In every post page, under the comments, there is already a link "Subscribe to Post Comments (Atom)" which is a feed. :)
If you want all the comments:

Anonymous said...

Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!