For today's post let's explore the principles in refactoring. I will try to give good answers to the following questions: Why should you refactor? When should you refactor and which code should you refactor? (And of course which code you should not refactor)
Why Should You Refactor?
I don't want to promote refactoring as a medicine to cure all software illnesses. However, it's a valuable tool that helps you with keeping your code clean. Refactoring is a tool that should be used for several purposes:
Refactoring Improves The Design Of Your Software
Without refactoring, your code's design will become old and will decay. As you and your teammates add more code to your repository you will change the overall structure of the repository. If no steps are made to improve the overall codebase, it becomes harder to grasp the design by reading the code itself. Refactoring is rather like tidying up the codebase. Work is done to improve bits that aren't really in the right place. Loss of the structure of the code has a cumulative effect.
Poorly designed code usually takes more lines to do what it has to do. With applying refactorings you improve the overall code length and reduce it. This will gain you much more confidence and will also help you maintain the bigger picture. An important aspect of improving existing code is to eliminate duplication. Check Problems with repetitive source code or better: Don'
t repeat yourself. The importance of this lies in future modifications to the code. The more code there is and the more code smells and duplications are in it, the more difficult it will be to add modifications to the code without further cluttering up the codebase.
Refactor early and often and improve the design of your code.
Refactoring Makes Software Easier To understand
One of the coolest things about refactoring is that it enables you to understand your code at a deeper level. When you refactor and clean up your code, it will teach you more lessons. It will show you ways to improve it further. Sounds too abstract? Let's look at an example.
Say you make a website with PHP procedural programming. You do not think of interfaces, object oriented programming and the like. It's a bad coding practice for sure. Now you decide to refactor your work. You introduce object oriented programming and refactor your code into objects. So far so good. This is really a difficult task, but we imagine all went smooth. Now the code opens a book of other suggestions to us - we could group some objects together, redefine some interfaces and make the overall solution to the problem a little easier. One could say we tie it more to a solution like one would see it in the real world. Refactoring makes refactoring easy!
If we had stayed with our procedural code, we would not have seen any of the stories our code has to tell us. Refactoring to the rescue!
Another important aspect concerning understanding software is that with refactoring your code becomes so clean, that you will not have to remember anything about it. You simply refactor if something seems not truly right. With refactoring you will also notice that you will have to write less code documentation in the form of comments. Your code will speak for itself! This is especially good when you, like me, cannot remember things very well. Using this technique, however, you will have to remember anything. All will be in your code.
Refactoring Helps You Find Bugs
Help in understanding the code also helps us with finding bugs. My current lead programmer is a lot better than me at finding bugs. He can read a lump of code - whether it be procedural or OOP - and see bugs in it on the fly. Alas, I can't. However, I have a powerful friend that helps me spot those bugs: Refactoring. When you refactor code, you work deeply to understand what the code really does and you put that new knowledge right back into the code with more refactoring.
Kent Beck once said: "I am not a great programmer. I am just a good programmer with great habits!" Think about it and make refactoring a habit. It will save you so much time.
Refactoring Helps your Programming Speed
At the end of the day, everything I said so far comes down to this: Refactoring helps you program quickly. This is probably the most important feature refactoring provides - it will help you make your lead programmer, project manager or CEO happy.
Improvement of speed? I hear you ask. Certainly, one improves quality with refactoring. However, improving design, improving readability, reducing bugs, all these improve quality, but they improve your speed? I am also a convinced advocate of the thesis that a good software design is the single most important foundation for rapid software development. Indeed, the whole point of having a good design is to make rapid development possible. With a poor design you can be fast for a while, but soon the poorly design code will slow you down. You will discover more and more bugs and will fix them instead of adding new functionality.
New simple features will need more coding as you patch a patch that originally patched a patch of your source code. A good design is essential for rapid development and refactoring helps you with this.
When Should You Refactor?
A good question indeed. Should you schedule refactoring? Twice a week? Once a day? Should the team spend two weeks of the month adding functionality and two weeks to refactor? If you have read my Introduction to Test-driven Development you will know what my opinion about this is. One should refactor all the time. In fact, you should program very consciously and critically review every line of your code as you write it.
There are a few guidelines about when you should refactor (and when not), though. Let's look at them now:
The Rule of Three
The Rule of Three is borrowed from Martin Fowler's book Refactoring: Improving the Design of Existing Code:
The first time you do something, you just do it. The second time you do something similar,you wince at the duplication, but you do the duplicate thing anyway. The third you do something similar, you refactor.
There is no need for much explanation here, eh? ;)
Refactor When you Add Functionality
A good time to refactor is when you add functionality. With adding functionality you add code that relies on third-party code or you directly modify third-party code. Always understand the code fully before you change it. Try to refactor it to make your understanding more apparent.
The other motivation to refactor when adding functionality is the opportunity to fix up old mistakes. As you want to add functionality you stumble upon old, smelly code. Quickly switch hats and fix it up. This may only take one minute and will save you hours in the longterm.
Refactor When You Need To Fix A Bug
When you (or your customers) discovered a miss-behaviour of your code you go out and try to find it. If you found the smelly code, try to refactor it to actively work with it. Have it covered with Unit Tests and improve your understanding of the problem. Then you will spot the bug and be able to fix it. You improved the design of existing code along the way. It's a win-win situation.
Refactor As You Do A Code Review
Code reviews are a great chance to spread knowledge of your code base among your team. Code reviews allow less experienced people learn from more experienced ones. Your code may be clear to you, but to your team it may not. Those organizations that do not implement regular code reviews would do better if they did.
Reviews allow you to sit down with your teammates and come up with new ideas on how to improve code. You may even find a new common refactoring we all could benefit from. With my current organization we implement code reviews regularly and it's really a good way not only to improve the overall architecture, but also to introduce people from other departments into your own work. Everybody will benefit from reviews. You learn about the codebase, learn new coding practices, have a social occasion, communicate with your team - it's the way to work together.
When you refactor someone else's code, you may come up with a few ideas on how to improve it. When you apply them, you can see what the code looks like with the suggestions in place. Had you not applied refactoring, you would never have read all the stories the code had to tell you and your code review would have been senseless. Actively review code of your teammates, refactor together and you will gain a lot of insight! Refactoring when reviewing code also helps the review to have concrete, measurable results. Not only do people come up with suggestions - no, they are also implemented them immediately.
If you want to refactor a large code base, using UML to communicate about your code may be a lot easier for your teammates than to show them the code itself. Actively develop your skills and you will find the best way to present your code that fits your situation.
When Shouldn't You Refactor?
This is a tricky question. You probably expect me to be such an advocate of refactoring that I would suggest there are no reasons why not to refactor. In fact, there are two situations when you should not refactor - at least not immediately:
- Your code is so messy that you better start from scratch. Remember that your code has to mostly work before you can refactor. If your code simply does not work and you cannot stabilize it, then go rewrite it from scratch. If that is not cost-effective, try to modularize it with strong encapsulation and refactor every module on its own. However, often it is better to simply rewrite it all.
- You are close to a deadline. Of course you want to please your manager. Meet the deadline and rush things in order to make it. As long as you do not build bugs into the code the productivity gain of simply hacking things in will be better when you are heading for a deadline. However, don't make it a habit. When you have time, refactor. If you have no time, it may indicate you do not refactor enough. Think about it. Also, if you decide to put off refactoring for a deadline, make sure you refactor the code immediately after the release.
Refactoring is great. Simple. There are really so many gains from refactoring - especially to spread knowledge about your software system among your team. Review code often, refactor as you add functionality, fix bugs or modify existing code. You not only will improve your design, but you will also make yourself a valuable colleague. People will be able to count on you.
Together with Test-driven Development, refactoring is the single most powerful tool of a programmer. It will help you enforce the following coding practices among your team:
- Less (code) is more
- Simplicity is a feature
- Prevent Hair-loss. Always
Refactoring helps you write better software, which should abide by the following:
- Speed and security are the foundation of any good user experience
- Put the user first
Also note that refactoring can mostly be done with automatic tools these days. For PHP there are not any as of yet. However, some are in the works. As a reference, I urge you to check out Rephactor.