Test -> Code -> Refactor, when should we start a refactoring?
refactoring, tdd
Solution
TDD is a great tool to keep you on track/on task. The problem with:
"Write failing Test" -> "Code/Refactor" -> "Write failing Test"
you propose, is it can easily become:
"Write failing Test" -> "Refactor" -> "Code" -> "Write failing Test"
or then
"Write failing Test" -> "Refactor" -> "Refactor" -> "Refactor" -> "Code" -> "Write failing Test"
which is what you want to avoid. By refactoring at the beginning of implementation, you are indulging in speculative development, and, not achieving the goal of the coding session. It's easy to head off on tangents and build things you don't necessarily need. If you have the feature working and tests passing, it's much easier to decide when's the right time to stop refactoring. And you can stop at any time because your tests are passing.
Additionally, you don't want to refactor when your tests aren't green.
A couple other small pts:
I think most of the literature has a slightly different definition what refactoring is. It's not "some changes to the system" or performance enhancements, but specific changes that don't change the behavior but improve the design. If you accept the definition, then performance improvements don't really qualify: they are normal development tasks that need their own acceptance tests. I usually try to frame these as end-user facing stories, where the benefit of doing them is clear. Make sense?
I think you're right that the TDD practice doesn't specifically address the design problems revealed during code reviews. (See reflections and pair programming for other solutions to this.) These tend to be bigger, cross-story issues built up as "code debt", and have to take some time to clean it up periodically. This could be a separate project, but I, personally, always like to do this as part of another "real" story. Last time I did this, we identified we had a problem, but ended up waiting a few weeks until we had a related story to work on it. We followed the TDD practice of implementing the new feature first-- even though we knew it was way wrong. But then we really understood what was going on and why it was messy, and then spent longer than usual on the refactor phase. Worked well.
Problem
The TDD circle is: ``` "Write failing Test" -> "Write Code to fit a Test" -> "Refactor" ``` At "Coding" step we are assumed to write code as simple as possible, just to fix a failing test. We should not write complex code until it is really required. The next step is Refactor. Should we refactor just written code? I think there is no real sence, as we should be happy with code as far as tests are passing. Probably Refactoring activity should be forced by some thing, like Code writing is foced by failing Tests. Here some possible factors: - The next test to be written requires some changes in system (refactoring) - Performance is bad. We need to improve it without breaking the functionality - Code review reveals that the code written is hard to understand. What other reasons you see to start the Refactoring? Also, is this scheme correct: ``` "Write failing Test" -> "Code" -> "Refactor" -> "Write failing Test" ``` or may be it should be seen as ``` "Write failing Test" -> "Code/Refactor" -> "Write failing Test" + "External factor (like bad performance)" -> "Refactor". ```