I’ll start off with this: Please refactor your code!
Now that I got that off my chest, what exactly is refactoring?
Def: “Code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behaviour. Refactoring improves nonfunctional attributes of the software.” – wikipedia
Now in layman’s terms. Refactoring is the ongoing process of changing your code – whether by code you focus on methods, classes or the whole code base all together – that does not alter the result. If programing is a journey, and the result is the destination then the code is the method of travel. Whether you go by boat (slow and boring) or by plane (fast and exciting) so long as you arrive at the same destination it is irrelevant.
But first let me show you why refactoring is possible in the first place. To help you better understand think of it this way.
The way we program is by setting a result and then charting a way to achieve that result. You always know what you want to code, the programing part is where you find out how you do it.
Imagine that the result is 20. How do you go about achieving this result. The first and most straightforward way is:
def twenty 20 end
Which is perfect, so long as you understand that the “twenty” method can only ever return 20 as a result.
But what about this:
def twenty 10*2 end
Same thing you might think, but not quite. As far as the machine is concerned, it is the same thing. As far as the user is concerned, it is the same thing because it returns the same result. But you as the author know differently.
You could well have reached 20 by division, subtraction, square root or by employing a secondary method. So why is this important since so long as you get the desired result it should be irrelevant how you go about it, shouldn’t it?
No, it shouldn’t and it isn’t. How you go about it makes all the difference, since you want to have as much reusability as possible. You want to squeeze out of this method all the juice it has. And to do so you want it to be as simple and abstract as possible.
Now that you know why refactoring is possible in the first place, let’s see why we should even bother doing it.
Take a second to understand how programmers work. We are humans, and as humans we have an intrinsic need to achieve the goals we have set our eye on. Knowing that, we will do all we can and work in such a manner to achieve this as fast as possible. This might be unnecessary when starting off with a new or “green field” project, but when working with legacy code we want to have a working model as soon as possible. First off to see that it actually works. Once we know that a). the desired functionality works and b). it integrates well with the rest of the application flow then it is time for clean up. Cue crickets.
Almost no one wants to be stuck with clean up duty. But to understand why refactoring is so important, think of it this way.
You are a 3 star chef. You have reached the pinnacle of your art and craft and you run a tight kitchen. A client walks in, sits down and places an order. You jump at the occasion, take out your ingredients, take out your tools and start cooking. 30 minutes later it is a masterpiece worthy of praise.
Then a new client walks in. He orders something new. You receive his request and start working. The pots are dirty from the previous use. Some ingredients that were necessary before but are not needed now are on the table. Your workspace is cluttered. Somehow you pull through but this time it takes you 40 minutes. No big deal.
Lunch time comes. A group of 10 people enter together and order together, each a different menu. Now you are in trouble.
The kitchen is a mess, everything is dirty and your workspace is cluttered. You cannot find your knives and you find yourself pressed for time. It is now 1 hour into lunch break and your group of “not so friendly anymore” clients are frustrated. They are invested in the waiting time and as such they have to stay, but they cannot understand why their food is still not ready. Rinse and repeat for all subsequent customers and you have a perfect nightmare recipe.
Now, even an amateur chef, or a non-kitchen staffer can quickly identify the problem and offer a solution. Just clean up your work space. Make sure that you can start with as clean a slate for each and every customer. And in case of ongoing traffic, just divide your tasks into cooking and cleaning. While the stock boils put back the ingredients. While the pan is frying, wash some pots and dishes. Always work on keeping your workspace clean.
Now if you substitute chef for programmer, cooking for coding and cleaning for refactoring then you can start to contour a better picture of why refactoring is such a big deal.
Imagine that like that poor tormented chef you had just one user, or customer that wanted only one application, only one design and you knew for sure that it will forever stay that way, unchanging as the day and night cycle. You could just fix him up his order and worry not about cleanup. But reality hits us, and hits us hard. Requirements change over time, the client finds out he wants or needs some other functionality, or even in the best case scenario where he knew exactly what he wanted and you serviced him fast and efficient, he will happily come back to you later on and ask for more development, more improvements and more expansions.
Now you find yourself sitting in that “dirty kitchen”, surrounded by bad and “smelly code”. Now suddenly you have twice the job to do but still the same alloted time.
Or worse yet, you work in a company that has a big app and the “client” is your boss. For sure you will have to churn out new functionality and design month after month. You have to work day in day out in the same “kitchen”.
We established why refactoring is possible and also why you should do it. So now let’s see what makes up good refactoring, what it is composed of.
You refactor or “clean up your code” to make sure it is in-line with the guiding principles of good programing. To make sure it ends up being SOLID code. You refactor your methods by extracting extra functionality to make sure it abides by the Single Responsibility Principle and thus has just “one job”. You do the same with the code in your classes. You separate Public from Private functionality. Hide off sensitive info and if necessary you can make more methods. 5 abstract and resusable methods are way better than 2 hugely complex ones. The choice between a couple of mega methods that are chock-a-block full of block statements, if clauses and complex functionality and a whole page full of simple – one or two line – methods tucked away neetly in the private part of you class all designed to send simple messages to your public interface.
You want to “DRY” up your code to make sure you get the absolute most from the most abstract and simple code base as possible.
And you want to do this not only for your code. Say you work in an already established application – you work with Legacy code. Please always leave the code better than you found it. You do this not only for yourself (in case you have to work on the same patch of dirt later on in the future) but also for your colleagues, both present and future. Think of it like a “pay it forward” type situation but amongst programmers.
So keep it clean and work will be a pleasure. Leave it dirty at your own peril.
Now the best way to efficiently refactor you code in a steadfast and seamless manor is by employing Test Driven Development or TDD for short. By employing this extremely powerful development tool you will soon come to understand that not only is refactoring simple and straightforward, but your whole code base more stable and scalable. But more about Test Driven Development, and how you should go about employing it, will be discussed at a later time.