By continuously improving the design of code, we make it easier and easier to work with — Joshua Kerievsky, Refactoring to Patterns
Refactoring is taking an existing, working, code, and make that code better.
Okay, but what does it mean “better”? It means better structured, better built, more readable, and more understandable.
Your code is easier to work with, it’s easier to add new features, easier to spot and fix bugs, easier to extend and maintain, and it’s a way to stop your code from gradually getting out of control.
If you’ve ever looked at a method that was getting a little too long, and found a few lines in it that belong together, separated those out into their own method.
And then replaced the original code with a call to that new method. Well, that’s a refactoring, that is the extract method refactoring.
It’s a collection of small, independent techniques for improving code that already exists. This code is already written, and it’s already working. We’re not changing what it does.
These individual techniques, each one is a single refactoring technique, and they are often very small, and each deal with one specific common issue.
There is no such thing as a set of rules or a specific order that just anyone can follow. But there is a set of techniques to help you to refactor your code.
Now if you’ve been writing code for awhile, you’ve almost done some of this already. But using the formal refactoring technique, brings more conscious awareness to that decision.
It doesn’t replace your intuition, but it gives you some more questions to ask:
A useful way to think about the refactoring techniques is to understand they can be grouped into several categories based on the different levels of the code they operate on.
Some of them concerned with individual methods itself, not worrying about class hierarchies or design patterns.
Then, there are refactorings where we take a slightly higher view. We’re still looking at the method but now being a bit more aware of our classes. Is this method in the right class?.
And, we can move up another level of abstraction, not focusing so much on the methods, but more on the communication between different classes. Is class A seem to do nothing but use class B’s methods and properties?.
And we’re even another level up. There are techniques really shine in a object oriented application. Are the clues that we should be using more inheritance and polymorphism or indeed less inheritance and polymorphism?.
You will see several refactorings that appear to be the exact inverse of each other. One refactoring technique has the name “Add Parameter”, but another, is “Remove Parameter”.
And it is, after all, perfectly understandable that the technique you need is sometimes the opposite of another one.
Refactoring is not debugging.
Your code already needs to work. It’s not a way to find bugs, you should have fixed those as soon as they happened.
So, it’s true, during the process of refactoring you may find bugs. But the moment that you start to deal with that. You have stopped refactoring and you have started bug fixing which is a very different mindset.
Refactoring is not performance.
This is another very common misconception that we cleaning our code up and that’s going to make it faster.
No, code performance is not the goal of refactoring nor even an expectation. But, our performance is!. We’ll be able to read the code and understand it faster. Not just individual pieces of code but the bigger application.
Refactoring is not adding features
If during this process you add a new feature, you are no longer refactoring. Because in refactoring we do not change the behavior of the code.
We might be doing a lot internally, creating new classes, moving functionality from one place to another, renaming, reorganizing. But the end result of the refactoring process doesn’t change the observable behavior of the code.
So, any end user who was using our application before would have no idea we did anything at all. We did not fix bugs, we did not make it faster, we did not add features.
So, why to do refactoring anyway?
Ok, so, refactoring is not adding features, refactoring is not finding bugs, refactoring is not about performance, but we refactor simply because we want to do those things.
Because well-structured code will make it so much easier to add new features and new capabilities. It will make it easier to start analyzing performance. So we’re refactoring to get the future roadblocks out of our way.
And we do refactoring for a reason. If no reason to refactor, then don’t do it.
If we have an application written and untouched since a long time ago. It works, it’s fast enough. There’s no conflict with any of their other systems and no features that need to be added.
It could be the ugliest code in the world, but, it doesn’t need to be refactored. Because it would be no reason to do so.
In the team culture, it can often be difficult for teams to get approval to spend time refactoring when it’s not part of the culture, because the benefits aren’t immediately apparent.
Yes, we’re not adding features, we’re not working on performance, we’re not fixing bugs, so why bother? We bother so we can do those things easier.
Refactoring is not an independent stage.
When you first learn about refactoring, it sounds like something you do as an independent stage. That you write an application and later you refactor it.
Well, you may need to do that from time to time if you have an existing code that’s a mess, but, the intention is that you start to do this all the time.
That as you write code, you refactor as you go. You write a new class or some new methods, check and test it, and then take a few minutes to scan and make sure it’s refactored as it could be.
In a team environment, a great way to learn refactoring is with code reviews or paired programming.
Bringing multiple sets of eyes to the same code. You find different people spot different opportunities for refactoring.
And, if you’re a solo developer, you need to pay a little more attention to applying the individual techniques, particularly those you wouldn’t naturally think about.
We won’t dig into each refactoring technique, what’s the problem it tries to solve, and how to apply it in the code. Most of them are easy to understand, and you can find them in “Where to go next” section below.Start with the common low level techniques, all the way up to more different levels.
First, you don’t need to know all the refactorings, just start using them.
In fact to learn them well, it’s more practical to pick just a handful set of techniques and start to actively apply those.
After learning even a few of these refactoring techniques you’ll find yourself naturally writing more modular code, better object-oriented code, of knowing the correct place to put a piece of functionality or a piece of data.
So, how to start? start from the bottom, the the lower level, basic refactorings, all the way up.
Things like renaming and extracting methods, shortening parameter lists, minimizing un-useful temps, making your conditions easier to read.
So, when you’re looking at a part of the code, just scan through that part of it two or three times.
What you’re not looking for is where I can apply X refactoring technique.
What you’re looking for are the things the will bring your attention. The things that make this code smells bad. And we use it as an indicator we have something to improve. This is what’s refereed to code smells.
So, duplicated code, a long method, long parameter lists, too many comments, and the list goes on.
But, some code smells don’t come from scanning, they will require close attention. Things like, data clumps or places to push down or pull up methods or fields.
Many of the most common programming IDEs, like Visual Studio, Xcode, and Eclipse, will actually help you do many of these refactoring techniques.
We’re changing code and that brings risk.
The single best way to prove that the changes you make when refactoring only do what you intend is to have a set of automated unit tests you can run on your code before and after.
Automated testing can be done using a test framework like Jnit in Java.
Automated testing all the way to test driven development or behavior driven development strategies are extremely complementary to refactoring.
When you’re comfortable with a set of refactorings and you want to take it further and explore more, then your resources should absolutely include “Refactoring Improving the Design of Existing Code”, by Martin Fowler.
This book isn’t intended to be read from cover to cover. Most of it is a catalog of refactorings. So it’s more of a reference than tutorial.
And as you get more comfortable, you may also want to look for resources on refactoring in your platform or environment. The principles are exactly the same. But there are often platform specific tips and tricks.
Thanks for reading! If you enjoyed this article, would you give me a few claps by clicking the 👏 button? It helps a lot!