Continual improvement of the structure of the code
Refactoring (Ref 2) is the process of changing the structure of code without changing its semantics, i.e. without changing its functionality. Constant Refactoring is an approach whereby before introducing any new functionality, the structure of the existing code is modified to be ideal for accepting the new code needed to implement the new functionality. By this process, the commonly observed ‘code rot’, the gradual degradation of code until it becomes a nightmare to maintain and modify, is prevented.
Originally known as “Semantics-Preserving Transformations”; a web search on this will bring up some early work.
Refactoring can be performed as a ‘one off’ exercise occasionally, or deliberately as the development proceeds. Each approach requires an appropriate supporting environment, to ensure a sufficient degree of understanding of the code by those people modifying it, and to ensure the modifications do not inadvertently change functionality and thereby cause the code to break. All refactoring should be accompanied with automated regression tests. Constant refactoring goes well with CollectiveOwnership and with DevelopingInPairs, though the latter is less necessary.
Refactoring should only be attempted if there is a good set of regression tests to ensure no errors are introduced. In addition, several circumstances have been identified where refactoring should not be relied upon to deliver changes cheaply: when 4th generation languages are used (also extra care needs to be taken with any non-OO language); with changes to programs where there are real-time dependencies; with late requirements that have major architectural impact. (These examples are adapted from Ref 1).
Boehm and Turner, in their book (Ref 1) claim that adding functionality later (as it is needed) rather than preparing for it as soon as it is needed costs more, and you would be saving money by preparing for it, building in the flexibility, straight away. However, we need to accept that costs of adding any functionality rise as the complexity of the system being modified rise. An important factor in this is that adding flexibility before it is needed increases the complexity of the system beyond what is needed. Boehm and Turner’s claim may prove to be false once this effect is taken into account, and overall costs are considered (that is, by adding flexibility early, all other later functionality costs a little more). This is a particularly important consideration when one considers the proportion of functionality “known to be needed” and prepared for, yet never actually implemented. Much of this inbuilt flexibility can become a millstone round the necks of future developers and maintainers.
In short, my opinion is that in reasonably small, fully agile projects, it does not pay to prepare for change. Once the team size grows or there are other reasons to start adopting less agile development approaches, adding flexibility in preparation for expected change reaches break-even point and eventually starts to pay off.