Imagine yourself in the following scenario, it shouldn’t be hard. You have been given a task to accomplish. To accomplish this task you realize that you are going to have to enter into (or at least look at) a piece of code that has been boarded up and labelled with one of those big “Condemned” signs. What course of action do you take? Do you perform cleanup where you are going to be working before you make the changes that accomplish your task? Do you shut your eyes, make your changes, and quickly flee? Do you do something else entirely?
Quite often when developers encounter some bit of code that is not to their liking, they feel as though it is their professional duty to immediately clean it up. The reasoning follows the lines that they cannot work with such a mess. In order to make there changes quickly, easily, and correctly, they first need to make sure that where they need to work is in a reasonable state. So the first course of action will naturally be to clean up and then perform their task.
It has been tried.
It has failed.
The problem with this approach is that when deciding what “cleanup” means you need to have some guidance as to what changes need to be made. You can, of course, work from design principles, code smells, patterns, and all of that, but those can only tell you possibilities and help find problems. They don’t help in pointing out what the correct solution is. In order to do that you need different information. You need to know what the area needs to do. Not only functionally what it needs to do, but also structurally. How does it need to change over time.
And there we see the problem with the “Cleanup -> Implement” process. The change to the code structure is happening before the information about what needs to change has been collected. The cleanup becomes speculative and easily spirals out of control. Rather than listening to the code as it complains about a specific change and responding to that complaint, you are deciding based on preconceived notions of “elegance”, “beauty”, and “cleanliness”, what that code *should* be.
So what do we do? Being a professional developer means that we cannot leave the code in the state that it is. We need to leave it better than we found it. We have to deal with improving it.
Luckily we already have in our hands the tools that we need to determine how to improve it. We have a requirement not only for what it must do, but also for how it needs to change (yep, that’s right, “how it needs to change”). Our first step is to gather information. Write a test that shows what the area of code needs to do for us. That test should fail, and with that failure we have gained information about what the code does. The next step is to change the code (even by just slamming in changes that disgust us) to make the code do what we need (as told to us by that failing test). During that change pay attention to what you are doing. What changes are you making? In what ways are those changes hard? Why are they hard? What would make them easier? More expressive? Now we have gathered the information that we need to be able to direct our cleanup. So go ahead and refactor. Fix those pains. Make the code expressive and clean.
Red -> Green -> Refactor
But be careful. Even those changes can become speculative. So how can you deal with that?
Make those cycles of Red -> Green -> Refactor small. Repeat them quickly and often. Split up your larger features into many small, quick passes through this cycle. You’ll end up passing over the code again and again. Sometimes you’ll “undo” a “cleanup” that you had just done when you get some more information on your next pass through, but that is OK.
This topic is near to me right now because, I recently fell into the trap of “Cleanup -> Implement”. I did this even though I knew better. I had worked with, and vigorously promoted, Red -> Green -> Refactor for a while. But sometimes you slip. I ended up wasting a lot of time doing things that I thought were advancing me. I got frustrated because I was making little progress. Then I finally stopped (after a prompt from my manager about how much more time I was going to take on that particular feature) and took a look at what I was doing. I realized that I didn’t know why I was making some of the changes that I was, just that I felt that I needed to. I switched to my process and within a short amount of time started to show progress toward my goal. A bit later I was done. The area was now cleaner with respect to its purpose and setup for the next person to come through and work there.