Tuesday, October 21, 2008

What refactoring IS

Let’s now state in the positive sense what refactoring is.

Refactoring is changing code internally, so that in some way or other, the code is internally in a better state. It aims to leave the code either clearer and easier to understand, or better structured, or containing less duplication, or simply with less code.

Refactorings change the code in such a way that externally there is no difference to the way the program functions or performs. If there has been a change that you can see on the outside – for example a button behaves slightly differently, or a calculation gives a different result – then this is not a refactoring. Often, a refactoring is done as part of a larger change which does change functionality – such as making a button behave slightly differently, or fixing a bug in a calculation – but the refactoring and the change in functionality are not the same thing.

Refactorings are objective improvements to code. Refactorings are changes which any reasonable programmer would agree have improved the code. It is true that, sometimes, whether a particular change would improve the code or not can be a matter of debate, but most refactorings are not in that category – most of them the change is a clear and easily acknowledged improvement.

A refactoring may be a change that is small and almost trivial, such as the renaming of a variable. Or it may be a change which is very large, such as separating out all the business logic which has somehow got tangled up with all the code dealing with the presentation.

Refactoring is a disciplined process, following careful steps to minimise as far as possible any chance of creating errors. Were ad-hoc improvements to the internals of a program in the past also refactoring? Yes, I believe they were. We would no doubt have performed them with as much care and attention as we knew how to do then. Refactoring applies best practices in making the changes in a disciplined way, and today our knowledge and understanding of how to perform the refactorings in a disciplined way has greatly improved.

Refactoring is a disciplined process in the same way that flying is a disciplined process. When, in 1903, Orville Wright had, what we term the first controlled, powered flight, it certainly required a large dose of discipline alongside much experimentation and daring. Nonetheless, the Wright brothers would no doubt look with great admiration and respect at the extensive and detailed modern-flight checklists. But regardless of the amount of discipline involved, flying is still flying. A flight done without performing any pre-flight checks is still flying. Similarly, refactoring done without any discipline is still, strictly speaking refactoring. Nonetheless, we should always seek to use the most recent understanding of how to perform refactorings with the most discipline possible. The person who does refactoring without being as disciplined as possible, is liable to end up in as difficult a situation as a pilot who ignores all pre-flight checks.
Refactoring is an ongoing process, to be applied at all stages of software development. It is something which you start applying even from the first week of coding (where code is growing at the fastest rate, and so often needs high amounts of refactoring to keep it in peak condition).

Refactoring is rather like a continual tug of war between the forces for and against the internal quality of the software. On the one side, pulling the software into a worse and worse structure internally are things such as tight schedules, sheer quantity of new code being added, junior developers, lack of experience of the technologies and so forth. On the other side, trying to pull the internal quality into as good a state as possible is refactoring. Yes, all the other forces on software are tending to pull it in a negative direction; that is why refactoring is so desperately needed, and also why it must be an ongoing process.

That is why, if we just focus our attention on trying to improve the causes of failure, even new projects are ultimately doomed. But this is what we like to do. With any new software development, we like to believe that if only this time we can get the specs written better, or develop in a more iterative way, or control the changes better, or ensure that the developers are more experienced, or any of dozens of other things – if only we can do this – then, ah yes, then at last, this time, this time our software will be great. This time, we will do things first time right, and we will keep them first time right.

No! No! No! This is doomed. The reasons that your next project will end up with the software gradually decaying beyond help are exactly the same reasons that the previous projects software has or will decay beyond help. Every cause that we have looked at is something that is sure and certain. Software entropy is a fact of life caused by all the things we have mentioned. Every cause that we have looked at will certainly pull your software in a negative direction. Improving each of the causes, whether it is by better specs, or better programmers, will only help to reduce these forces of entropy pulling software in the wrong direction.

There will always be factors pulling a program the wrong way, tending to make a program get worse and worse. There are many causes of software decay, pulling the program inexorably in the wrong direction; it is the natural lot of a programmer’s life. By all means, let us try and reduce the causes of software decay to a minimum. But the forces which pull the program the wrong way in quality will still exist and the program will still get worse.

There is only one thing which we can do to pull a program in the right direction, that is by a constant and continual application of refactoring. Refactoring is the one thing where we actively try to pull a program in the right direction, trying to make it better and better. The only way we can hope to maintain the long-term health of our programs is if we have some force which pulls the program in the right direction in quality; that force is refactoring and our programs cannot survive without it.

Refactoring is also like a person and exercise. Adding code is like eating food, refactoring is like taking exercise. As you eat more and more, and take no exercise, the tendency is to get fatter and fatter. When you exercise, you help the body to stay fit and healthy. Refactoring is to software as exercise is to people: it helps keep the program in a fit and healthy state. The more food the man eats (=the more code development which is going on), the more exercise the man needs to do (=the more refactoring is required). Just as if a man keeps eating food, he will become fatter and less flexible and more sluggish, so it is for your software, as you add code, unless you constantly refactor, they will become more and more puffed up with duplicate code, and slower and slower to work with and change and enhance.

See my book The Refactoring Workout for more on refactoring.

No comments: