Refactoring Needs More Than Tests
When Extreme Programming first started becoming popular, there was a lot of discussion about the interplay between the practices. XP had twelve practices at the time and it was obvious that you couldn’t just yank one out and hope that everything would be okay. Try 'Collective Code Ownership' without 'Pair Programming' for instance. Sure, a team can hobble along that way, but unless they apply some substitute practice, the code devolves into bug-ridden rot.
Refactoring is no exception to this rule. It has its preconditions. One of the clearest preconditions for refactoring is the existence of tests. Martin Fowler is pretty explicit about that in his Refactoring book, and everything I’ve experienced with teams backs it up. Want to do make things better? Sure, but if you don’t have tests to support you, you’re gambling. Can you do a little refactoring to get tests in place? Yes, I advise it, but when you start to do significant refactoring, you’d better have tests to back you up. If you don’t, it’s only a matter of time before your teammates take away your keyboard.
So, yes, testing is a precondition for refactoring, but there is another. I can illustrate it with two scenarios:
- A project has a very large code base. They’d like to start refactoring, but they do their development in an interesting way. They have several teams of people work on several releases at once.. in the same code base. They only integrate once a month or so. How much would you change structure if you knew that someone else was modifying the code, and you would only find out in a month?
- Another project depends heavily on code supplied by a vendor. The project has year long release cycles and the vendor gives them updates every few months. Every time the project gets an update they have to apply patches for everything they’ve changed – from the beginning. You can imagine what the last month is like.
The thing that is common in both of these scenarios is a hidden precondition: you can only refactor when you are working on one code base. What do I mean by "one?" Well, it’s often easy to trick ourselves into thinking that we have one code base. We refer to it as "the code" or the "the code from the vendor" but if the code exists in two different views at the same time, and people can modify it independently, it isn’t one code base anymore.
I’m going to offer a weird analogy now. I'm sorry, but here it goes.
Some people who study cognition and consciousness have the view that self-awareness is a function of time: it doesn't exist in the instants. Our brains run many parallel processes and we each see ourselves as an -I- only because we our brains construct that view by piecing together the differences between our perceptions across the seconds, producing the sensation of a whole self. In short, we integrate frequently.
The same trick happens with code. If we integrate frequently, we effectively have one code base, or at least a reasonably comfortable illusion of one code base. As we integrate less frequently, the pieces stray. It’s no longer a single code base. And, refactoring, to be practicable, needs to be consistently applied in one code base.
Another scenario I see a lot of is where you've got separate teams for each layer: [UI, model, persistence] for example. In this case, refactoring the model gets tricky because the UI depends on a published API. But as long as what is published remains sacrosanct, you should be able to freely refactor what lives below the API. The trick is ensuring that clients aren't using the un-published parts and that the API really does remain intact. If we can do that effectively, would you view the goo below the surface as a "single code base"?
I think I hear implied solutions and just wanted to be sure. There are two solutions, integrate more frequently or don't get into either of those situations.
I really like the idea of teammates taking away your keyboard for bad code: can this be included with the other XP practises? It can be like the sinbin in hockey. In fact, this can also be a useful technique to encourage pair-programming - the coach can remove a one keyboard (or computer) from the bullpen every night, until there are only enough for half the team :)
That's a description of the real problem right there. There are also branch-and-merge souce control tools that can help with these problems, but it seems like the coupling between the two projects described int he second scenario is way too tight.
Add Child Page to RefactoringNeedsMoreThanTests