Refactoring
An incremental and feature driven approach to the development of software systems can produce sub-optimal architectures compared to a waterfall model, as discussed previously. One of the advantages of BDUF is that the complete up-front design is optimized for a full-featured release. Components are well-integrated and duplication is minimized.
On the other hand refactoring is needed to pay off the “technical/design debt” which accrues over time, especially when incremental and evolutionary design results in a bloated code base, inflexible architecture, duplication, and other undesirable side effects.
The metaphor of technical debt was used by Ward Cunningham (creator of the Wiki) to describe what happens as the complexity and architecture of a software project grow and it becomes more and more difficult to make enhancements. Figure 16 illustrates this concept: as the software product degrades over time, the cost of change increases to the detriment of the customer responsiveness.
Figure 16 - Technical Debt Curve
This concept of technical debt has become popular as it can be understood by both technical minded and business minded people. Just like credit debt, technical debt accrues interest payments in the form of extra effort that must be made in subsequent development cycles. Management can choose to pay down the principal on this debt by refactoring, and keep the future cost of change as low as possible.
Controlling the cost of change is very important for an Agile project, since the philosophy is to embrace change. Indeed one of the twelve principles of the Agile Manifesto is to welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage. (see Table 3 - Principles Behind the Agile Manifesto.) Therefore refactoring is critical to keeping the agile process sustainable through the pay-down of technical debt.
Holistically speaking, one could argue that true Agile is not only about the agility of the development process, or the team, but also about the software product itself. In other words, a “Systems Thinking” perspective would suggest that the software product itself is part of the system under study here, in addition to the people, processes, and tools. If the software is constantly refactored to keep it easy to adapt and evolve along with the requirements, needs, or market environment, then the project can truly be agile. Perhaps one of the problems with Agile adoption in large-scale government programs is with attempting to employ it on long-running legacy programs that are already deep in technical debt.
Many agile methodologies (in particular XP) consider refactoring to be a primary development practice. Refactoring has the disadvantage that it takes extra effort and requires changing baseline software without any direct or apparent ROI. A project manager may ask “why are we spending effort re-designing portions of the system unrelated to the next planned set of features?” This is when the technical debt metaphor comes in handy as a tool for communicating the business impact of design and architectural decisions.
The project management may still resist refactoring with: “If we do refactoring, we will have to re-test and re-certify existing baseline functionality, at added effort and cost to the project!” Any change has the potential to reduce the maturity and the stability of the software, requiring regression testing and revalidation of the baseline feature set. This is why it is advantageous to practice refactoring in conjunction with test-heavy practices (e.g. TDD) and Continuous Integration techniques.
An example of a software organization that embraces refactoring as part of its software engineering culture is Google. The following points, taken from Google’s Agile Training (Mcfarland 2006), summarize some of the reasons behind their embrace of Refactoring:
· As code ages, the cost of change goes up
· As Google grows, the percentage of code in maintenance mode grows with it
· We need to keep code flexible, so we can change it to suit new market conditions quickly
· It’s not important if all you’re trying to do is get new products out. (Smart programmers can develop very good applications without tests, but those applications will be much harder to maintain.)
A final note on refactoring and technical/design debt is that this phenomenon can be observed at the enterprise level. We observe that much of the work in net-centric architectures, which involves evolving an ecosystem of silo’d systems towards a system-of systems architecture using technical approaches such as SOA (Service-Oriented Architecture), can be understood through the lens of technical debt as grand-scale exercises in refactoring.