It is the neglect of timely repair that makes rebuilding necessary
Delivering current business value to users and stakeholders is the goal of software development. Constantly changing technology, superimposed on the evolution of business and user paradigms, presents obstacles to maintaining and increasing that business value. In view of the increasing complexity of code systems and the corresponding gradual obsolescence of legacy code, two paths to the future exist:
- Keep adding features towards an eventually unmaintainable “throw away” state
- Continuously modify the system to provide a foundation for efficiently delivering not only the current business value, but future business value as well – the Agile model.
The second choice has many distinct advantages. Using this model, the useful life of an enterprise’s investment in software assets can be extended as long as possible, and users can continue to experience a flow of value for years to come. One of the key Agile methods aiding in developing and maintaining software involves ‘refactoring’. This article covers different aspects of refactors as team backlog items. To find more about refactoring as engineering technique, see the references in ‘Learn More’ section.
The essence of refactoring, as borrowed from engineering, lies in modifying any entity, such as a module, method, or program in such a way that its external appearance, i.e. its functionality, remains unchanged. This is in distinct contrast to program modifications that might change the functionality of a module.
Refactors may accomplish such things as increases in processing speed, different sourcing of internal data, or security matters, to give a few examples.
One type of refactoring involves streamlining some aspect of the code to make it more efficient, more maintainable, or even more readable. The end-user or customer will experience no substantial change, except, for example, decreased response time. It is a principle of refactoring that each change made be tested immediately to verify the correct accomplishment of the desired goal. A refactor may be broken into a series of sequential micro-refactors in order to accomplish a larger goal, retaining the necessity to test each change micro-factor in its turn to assure correctness. This iterative process preserves and demonstrates the integrity of the software at any stage, which inevitably makes the software more maintainable.
Role of Refactoring
Refactoring is a globally safe method of maintaining modules in a released (i.e. tested and accepted) system of any size without causing adverse effects outside that module. It is safe because the process of refactoring involves iterative testing to satisfaction before the refactor is released to the environment (usually the affected module, but refactors can be shared.)
Importance of Refactoring
Refactoring is as integral to Agile as the daily standup or iteration demo. As such, it is a material part of the art and science of Agile development, and of course, this short article only touches the surface. Agile teams would be wise to read and discuss any or all of the following texts on this important topic. Refactors have special meaning in Agile development. As Agile development eschews the Big Up Front Design (BUFD) process, the system will need to evolve rapidly as new user needs and emerging technical factors are discovered. Therefore, refactoring is as integral to Agile development as a timebox or user story, and it must be a first class component of software development.
SAFe emphasizes the importance of keeping all work visible, including refactoring. Like user value work, it must be planned for, estimated and prioritized at all levels of the organization. At the Portfolio Level, the Architectural Epic Kanban establishes the flow of Architectural Epics that build the Architectural Runway for future functionality. Agile Release Trains consume new Architectural Features, typically bound to a specific system and necessarily completed in a single PSI.
At the lowest level, these larger backlog items get split into refactors, now a special type of Team Backlog item that can be implemented by one Agile Team within a single iteration.The team is the closest to their code assets, and they will have no shortage of ideas for solutions as well as areas that must be improved.
At higher levels, Portfolio Managers, Product Managers, and Product Owners must understand the business value of refactoring, and prioritize it accordingly.
Sources of Refactors
Refactoring plays an important role in Agile, and refactors arise from diverse sources and support many aspects of program and team performance. Figure 2 shows several refactoring sources coming from different program directions:
A refactor can be required by a business feature or can be a part of larger refactoring initiative defined as an architectural feature. User stories may also require some refactoring of code and lastly, the accumulated technical debt may drive the team to put refactors in their backlog. Thus refactors serve both intentional architecture and emerging design. Sometimes refactors may be necessitated by a nonfunctional requirement (NFR). It is important to emphasize that not all team’s refactoring effort comes in the form of specific refactoring stories. Much of it should be “in-line” clean-up work, done while implementing user stories. Such work should be factored iton the estimate of the corresponding story (see continuous refactoring techniques described in (Ref , , ). Specific refactors, however, represent a larger pieces of redesign that need to be planned and tracked as separate backlog items.
Specifying and Estimating Refactors
Properly specifying and estimating refactors is at least as difficult as doing the same for regular user stories. This is natural as a single refactoring can change the flow of multiple system behaviors. The following methods are useful to cope with the complexity:
- Use group analysis and estimation of refactors as different people were implementing different user stories during the course of the past iterations and may figure
- Run a short design workshop for every refactor
- Keep it short (10 – 30 mins)
- Use whiteboards
- Avoid abstract statements.
- Talk in concrete examples of internal system behavior and interfaces that will undergo refactoring
- Use existing models that represent various views of the system
- Consider potential alternatives and their impact
As with user stories, splitting refactors is important, as it helps to sustain better development flow for the team due to the incremental approach. Below are some of the useful method of splitting refactors, and some examples for each (Table 1):
|1. By User Scenario or User Story Refactor incrementally in a story-by-story or scenario-by-scenario mode, or else somehow identify the functional areas as a basis for increment.|
|Improve DB queries and introduce data caching so that the system would run faster||…Refactor all user management functionality …Catalog browsing functionality …Checkout functionality|
|2. By Component Refactor first everything related to a single component and then move to the next one.|
|Change indexing process to batch processing so that the process would take at least 2-3 times faster for average web page||…For parsing (parser component) …For entity extraction (analyzer component) …For storing in the index (index component)|
|3. Interface / Implementation Create new interfaces and wrap up old functionality into it as step 1 and then refactor the functionality itself as step 2.|
|Extract all parsing parameters into an xml configuration file so that that the process can be tuned easily without changing the code||…Install PINGID Protocol server and test with mock identity provider …Read configurations from file in any format …Refactor configuration functionality to support certain structure and schema validation|
|4. Strangle Component Incrementally move the functionality of the component to other components until everything is moved and then it goes away.|
|Replace database with custom search index so that indexing and search performance would improve 10-20 times||…Move index data to custom search index first …Move entity dictionaries|
|5. Inline Refactoring / Extraction Refactor the functionality in-line where it currently is, but then extract it and encapsulate into a component or class or method / function.|
|Replace current ad hoc parsing with grammar-based functionality so that changing parsing rules would become easy and without coding||…Refactor the code (as is) to use grammar notation …Extract all grammar-related functionality into a grammar engine|
|Table 1. Methods of splitting refactors|
Acceptance Criteria and Demonstrability
Defining acceptance criteria for refactors is extremely important, as it resolves ambiguities that are so common in system redesign. The following example shows certain aspects reflected in acceptance criteria that could be otherwise missed or misinterpreted:
Just as in the case of user- and technical-stories, acceptance criteria can very often be used as a basis for splitting. Splitting refactors in this way can either overlap with some of the methods above or provide deeper context-dependent splitting capability. So, the first step in Figure 3 would be to “…make synchronous non-configurable batch processing with single query to dictionary but without the debug logging”; then “…add capability to read batch size from the file”; step 3 would be to “…process items asynchronously”; and finally “…add debug logging functionality”. Agile teams demonstrate the results of their work after every iteration. This is applicable to all backlog items and refactors are not the exception. Good Agile teams know that everything is demonstrable, no matter if it is a user story that has a UI or a refactor that is mere improvement of system design. So, in the example above (Figure 3) the team would possibly want to demonstrate the following:
- considerably reduced processing time on a few web pages compared to previous benchmark
- dependency of processing time on the size of the batch, which can be configured from the file
- code snippet for asynchronous processing
- debug log file that captures all operations described above
- number of queries to dictionaries per batch (from the log file).
It is easy to notice that some of these are interesting to stakeholders (like #1), others are especially valuable to the team as it immediately shares the information about internal organization of the code. At this touch point product owner also synchronizes better with the team and starts understanding their need for refactoring deeper.
Team Skill and Culture
Refactoring is a mandatory skill for teams in the Agile enterprise. Thus refactors should routinely appear on the team backlog and should accompany the in-line refactoring factored into a story estimate. Sharing the refactoring skills within the team and across teams is very important. System Design Community of Practice (CoP) should pay a lot of attention to refactoring techniques while Scrum Masters should help their teams master efficient approaches to of specifying, estimating, and splitting refactors as well as defining acceptance criteria. Product owners should be able to embrace value in refactoring and groom refactors in the backlog.
 Fowler, Martin and others. Refactoring: Improving the Design of Existing Code. Addison-Wesley, 1999.
 Martin, Robert. Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall, 2008.
 Wake, William. Refactoring Workbook. Addison-Wesley, 2003.
Last update: 16 January, 2013
© 2010-2013 Leffingwell, LLC. All rights reserved.