Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations. Each transformation (called a ‘refactoring’) does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it’s less likely to go wrong. The system is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.
—Martin Fowler, from refactoring.com
In Agile, we constantly seek opportunities to simplify our code, removing duplication and making it more expressive of our intent. This is achieved through the process of Refactoring.
The use of automated Unit Tests supports Refactoring in that it is very simple to determine if a change to the code has affected any other parts of a system. As each change is made, the tests are run in full to ensure that the system as a whole is still in an operative state. This also promotes the value of Courage.
In object-oriented languages, Refactoring is used to put into effect good OO design principles. A classic example is the Single Responsibility Principle, in which a class should have only one reason to change. The process of Refactoring should result in numerous small classes with minimal dependencies and only a single reason for changing.
Refactoring is not to be confused with larger changes to code, such as Restructuring and Rewriting. Refactoring is a process that occurs every few minutes (or edits) and, as Martin Fowler states above, each small change has a cumulative effect of improving the design of the code.
Over time, code becomes more brittle, less cohesive and more tightly coupled as changes are made. Changes in team members will result in having people work on code that they didn’t write and thus don’t necessarily understand. As such, changes that they make may have unintented side-effects that may not manifest themselves immediately. The developers (and their managers and customers) fear making changes to existing code – the testing effort required to validate the changes is quite prohibitive. Similarly, managers have traditionally seen changes to existing code as unnecessary tweaking that costs money and produces little short-term value. Developers are told not to touch code that isn’t broken, regardless of its state.
This is known as Technical Debt.
What results is not unlike the debt on a high-interest credit card. If you only make the minimum payments on the credit card but continue to rack up charges, eventually the combination of high interest and the principal debt becomes overwhelming.
Refactoring is a way to deal with code debt. With most credit cards, if you pay off all of your purchases before the statement date then no interest is charged. The same applies to Refactoring – if you apply it in small increments supported by tests, the code debt is quite low and manageable. A system with low or no code debt can be modified easily since changes will be relatively isolated. A symptom of code debt is that a single change in one class requires changes to multiple areas of the code.