
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.
Ref 2
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.