These patterns are intended to be used by the community so it is the community the best suited for decide their content.
"By definition, you only refactor code that is already working, which where I come from is scary. Working code is a valuable asset since it is hard to get right (...) and takes time. Touching working code is always a risk and so there should be a darned good reason for doing it" [1].
Pattern Name: Backtrack If Refactoring Fails
Problem
How do you assure the quick recovery of the code in case the refactoring process introduces irreversible changes?
Context
You are applying refactorings as the source code evolves. You followed RefactoringInVerySmallSteps, but the volume of changes involved in each refactoring is big enough that the code cannot be taken to its original position in a simple way.
Forces
Maintain backup copies of the state of the code before applying refactorings. Use version control systems to carry out this activity. A common routine to follow can be: check out the code to be changed, apply the refactoring, test the changed code, and then, if things went well, commit the new version, otherwise roll back the changes.
Resulting Context
Keeping backup copies of the source code using version control systems offers a safe method to carry out refactorings without fear to lose the functionality already programmed. If your refactoring is defective, you can back out the adjustments, so you'll never need to rewrite already programmed code.
You should pay special attention to rolling back a source code that is connected with external data sources, because there are no clear ways to roll back them to the point that matched the code rollback without significant data loss or, sometimes, there is no way to synthesize previously required data from newer data sets.
Rationale
"Program testing is an effective and practical way of improving correctness of software (...)" [3], however, "(...) no system can be completely tested" [4]. Therefore, there are no mechanisms to assure that after applying refactorings, errors will not be introduced in the code in a manner that they can't be detected by existent tests. The development team needs this pattern to be sure that refactorings will not decompose the performed work. This pattern breaks the barrier created by fear and allows people to run the risk of applying refactorings.
Origins
William Opdyke in his doctoral thesis [2] exposed "one way to prevent errors from happening would be to save the current version of a program before each refactoring, apply the refactoring (...), and then recompile the program. If an error is flagged, fall back to the old version".
In the WIKI pages about refactoring, Falk Bruegmann wrote "(...) make sure you can rollback the refactoring without to much work in case the tests do fail. (...) at least for larger changes, have a backup copy of the state of your program (...)" [5].
Acknowledgments
[1] Robert X. Cringely. Refactoring Refactoring: Sometimes (Even in Computer Programming) What Everyone Knows Isn't Always Correct. Available at: http://www.pbs.org/cringely/pulpit/pulpit20030508.html. 2003. Last confirmed: July 01, 2004.
[2] William F. Opdyke. Refactoring Object-Oriented Frameworks. PhD Thesis, University of Illinois. Urbana, Illinois, 1992.
[3] Yoonsik Cheon, Gary T. Leavens. A Simple and Practical Approach to Unit Testing: The JML and JUnit Way. Proceedings of 16th European Conference Object-Oriented Programming (ECOOP), pp. 231-255. 2002.
[4] Ivar Jacobson, Grady Booch, James Rumbaugh. El Proceso Unificado de Desarrollo de Software. Addison - Wesley, 2000.
[5] Wiki Pages About Refactoring. Available at: http://c2.com/cgi/wiki?WikiPagesAboutRefactoring. Last confirmed: June 26, 2004.
Author: SantiagoValdarrama?
See Also:
May I also point out that there is more to this than the code.
Particularly troublesome are the changes often made to the data stored and retrieved by the code. This is often, but not always, database storage. Spectacular failures have occurred where the code has been rolled back, yet there was no clear way to roll back the database(s) to the point that matched the code rollback, without significant data loss or, sometimes, no way to synthesize previously required data from newer data sets.
I would suggest that this issue is at least as important as simple preservation of the code.
Garry,
Your comments were included as a force of the above pattern. Also, there is an explanation in the resulting context section. You can see your name as part of the Acknowledgments section.
--- SantiagoValdarrama?
The idea of backtracking assumes your working with something like a HEAD revision in your VersionControl. In something like SubVersion, you could just branch at the start of your Refactoring, and only MergeChanges? back to your HEAD if they are successful. You just delete your branch if your refactoring fails.
This gives you a Transactional style approach
--- KevinWheatley?
Yes Kevin. That should be a mechanic to follow this pattern.