Refactoring source code can be likened to reducing a mathematical expression to lowest terms.
Let the following fraction represent the first version of a program.
1+4 ––– (1) 3*5Obviously it can, and should, be simplified (refactored)
5 –– (2) 15and indeed, again and again, until it is in lowest terms.
1 – (3) 3In algebra, the simplification is achieved by applying mathematical rules. The purpose of a derivation (or proof) is to stepwise change the form without changing the value. Training and peer review are used to help insure valid results.
In software engineering, the simplification is achieved by refactoring. The purpose of refactoring is to stepwise change the implementation without changing the behavior. UnitTests and/or RefactoringTools provide confidence that the results are valid.
In both fields, the goal is to achieve a form that fosters maximum understanding, clarity and utility. This goal is typically achieved by minimizing the number of symbols and/or by conformance to standard representations. In both fields, the simplification steps should be small enough to ensure their correctness.
The metaphor can be extended. For instance, consider the word problem. The first step is to "set up the problem." Once correctly translated into mathematical notation, the answer is implied by the resulting form, ala equation (1), but is unlikely to be in lowest terms. A mathematician who stopped here would not be regarded as competent.
A first program is like translating a word problem into mathematical notation; it only "sets up the problem" and it is a far more complicated problem. The act of coding is the most effective method for exploring the problem domain and so the resulting first program is heavily influenced by the chance order of events during the encounter of programmer with problem. Because of complexity and chance the first program will be very far from lowest terms - it will need significant refactoring.
If the metaphor were perfect, a programmer who stopped here would not be considered competent either, but because computers are now so fast, the first program actually has some utility. In the mists of time, when computers were slow, such programs were in fact regarded as incomplete. They were aggressively refactored, but for speed and to reduce their demands on hardware resources. Today, the goal of refactoring is to maximize MaintainAbility. Once we have proved a theorem (refactored a program) we want to use the results to prove more difficult theorems (write solutions to harder problems).
Books on programming typically offer code snippets that show how to use the language, construct a data structure, or implement an algorithm. For teaching refactoring we need a series of code snippets. The following format is tedious to type, but easy to read.
class Sam { | class Suess { void same() {} | void same() {} void unique() {} | }; }; | | class Sam : Suess { class Iam { | void unique() {} void same() {} | }; void unique() {} | }; | class Iam : Suess { | void unique() {} | };The above example fits the pattern in ChooseSuperClassesByRefactoring.
-- AllanGoff