- Refactoring vs. Technical Debt
- Broad vs. Narrow Consideration
- Stop Digging the Hole and Deeper
- Fill in the Hole
- Broadly Attack Refactoring
- Make the Business Case
- Talk About the COST
- Don’t Attack Too Much at Once
- Invest in Test Automation
- Find Release Tempo Opportunities
- Wrapping Up
- Make it an Ongoing Investment
Yet, as with anything in life, there were challenges and room for improvement. I remember attending a noteworthy backlog maintenance meeting with one of the teams. This particular team was incredibly strong, so I simply attended to check how well they were grooming. To be honest, I was hoping to share some lessons from their approaches with some of the less experienced teams. Jon was one of the lead engineers on the team. He had been a Scrum Master for a long while, so his agile chops were mature and balanced. However, I was surprised when the following happened:
Max, the Product Owner introduced a User Story for the second time in maintenance. The team had already seen it once and had realized two things:
1. It was bigger than a Sprint’s worth of work for the team (call it an Epic or non-executable Story), and
2. They needed more information about the legacy code base surrounding implementing the story.
So they created a Research Spike that represented technical investigation into the story. This session was the first time the team had got back together after their learning from the Spike. Jon had taken the lead on the Spike, working with two other team members.
He went over the implications from a legacy code base perspective. Jon started the discussion. He and his small team recommended they split the Epic into three sprint-digestible chunks for execution. Two of them had a dependency, so they needed to be worked in the same Sprint. The other needed to be worked in the subsequent Sprint in order to complete the original Epic.
Jon and his team had reviewed the legacy code base and said, in order to do the work properly, it would take a total of approximately 40 Story Points. However, he pointed out this might be perceived as excessive and approximately 25 of those points would be spent on refactoring the older code base. The specific breakdown was 18 points for the new functionality and 25 points to refactor related legacy code.
The Product Owner excitedly opted for the 18 points and deferring the refactoring bits. Jon and his small Spike team wholeheartedly agreed and the entire team went along for the ride. From a backlog perspective, the 18 points worth of stories became high priority and the refactoring work dropped to near the bottom of the list.
And the meeting ended with everyone being happy with the results.
I decided not to say anything, but I left the room absolutely deflated with this decision. It was opposed to everything we had been championing at an agile leadership level. Clearly put, we wanted the teams doing solid, high quality work they could be proud of. In fact, all of our Definition-of-Done and Release Criteria surrounded those notions.
If the cost of this Epic was approximately 40 points to do it right, then that was the cost… period. Splitting into the parts you agreed with and the ones you didn’t agree with, were not really options. Sure, each team needed to make the case to the Product Owner surrounding the why behind it, but it was not a product-level decision. It was a team-based, quality-first decision. De-coupling the two broke our quality rules and that decision would haunt us later as technical debt.
To close this story, I used my not-so-inconsequential influencing capabilities to change this outcome. We decided this Epic was important enough to do properly and the approximately 40-point cost was worth the customer value. In other words, we made a congruent and sound business decision without cutting corners. The team fully appreciated this opportunity, without second-guessing and guilt, to deliver a fully complete feature that included the requisite refactoring to make it whole.
Now, I only hope they continue to handle refactoring opportunities the same way.
Refactoring Versus Technical DebtAny discussion on refactoring must also include the notion of technical debt. The two are inextricably linked in the agile space, meaning, refactoring is a way of removing or reducing the presence of technical debt. However, not all technical debt is a direct refactoring candidate. What I mean by that is refactoring typically refers to software or code, while technical debt can surface even in documentation or test cases. So it can be a bit broader if you want to consider it in that context.
Broad Versus Narrow Consideration
Typically any discussion on refactoring is embedded in the code, usually the application or component-level code in which you are delivering your product. Sometimes, although much more rarely, the discussion extends to supporting code such as automation, build infrastructure, and supporting scripts.
I would like to make the coupling even stronger between technical debt and refactoring. To me, you refactor away technical debt. You identify the debt and the effort to remove it is refactoring. Code is a primary place for it, but I believe you can and should refactor other items, for example:
- The graphical design on the wall that no longer represents the design of your product
- The test case (manual, automated, or even exploratory charter) that is no longer relevant given your products behavior
- The wireframe that has iterated several times with the code and is now out of date
- That wiki page that speaks to new team members on how to build the application or other team-based documentation
- The test automation the team broke during the last Sprint and failed to fix
- The tooling everyone uses to measure application performance, but needs an update
- The team measures on throughput that have not been updated and no longer apply because the team moved from Scrum to Kanban
- Or the current process a team is using for story estimation that is not serving them very well
Clearly I lean towards a broad-brush view to refactoring responsibilities and connecting them to the various kinds of technical debt. From my perspective, I’d recommend you deal with it as broadly as possible within your own contexts.
Stop Digging the Hole Any DeeperAlmost a no-brainer initial strategy is to stop making your debt worse! This involves all new functionality. For every story you develop, make sure your technical debt isn’t getting worse. You want to hold the line on new work and make sure you are doing things right.
While I was coaching at the email marketing SaaS firm, a trigger word in our team discussions was “hack.” Whenever a team member spoke about hacking something together, we knew it would create technical debt and need refactoring lator. So we worked incredibly hard to avoid “hacks.”
Fill in the Hole
Once you show the discipline to hold the line on new work, you can go back and start refactoring legacy crud that has developed over time. This usually is a longer-term strategy in many organizations and requires great persistence. It is also a moving target to some degree, so patience is needed as well.
I like to engage the team in identifying refactoring targets. Avoid the we-have-to-fix-everything syndrome and ask the team for the highest priority refactoring targets by way of value–for example, removing impediments to the development team’s efficiency or capacity.
Broadly Attack Refactoring
Balance is a key in refactoring. Attack technical debt in all its forms and do not necessarily focus on one component or type of debt. You want to look at your entire codebase, tool-base, script-base, documentation-base, etc., in your retrospectives and select high-impact, high-return refactoring opportunities. Then apply a bit of relentlessness in pursuing and improving those areas.
Make the Business Case
Even though I talk about refactoring being an organizational and team responsibility, it does not get supported by magic. Teams need to identify (document) their refactoring work on their Product Backlogs. The business case for each improvement needs to be explored or explained, particularly if you are going to get your Product Owner to support you. So yes, it is a responsibility. But you need to put the rationale and the ROI in clear business terms. Then connect the dots back to the ROI after you have refactored the code, perhaps discussing or showing improved implementation speed in a Sprint Review.
Talk About the COST
Remember that refactoring often has a cost in time-to-market. Bugs take longer to fix or cluster in ways that influence customer confidence and usability. Maintainability is a strong factor in being truly nimble and creative. At the email marketing firm we often selected and justified our refactoring targets by how they would support our future product roadmap and support faster implementation times.
Then, when we had completed the refactoring, we would look back on those improvement estimates and speak to the reality of the improvements–connecting the dots, if you will.
Don't Attack Too Much at Once
One of the hardest things to do in many organizations, those with debt-rich legacy systems, is to prioritize the technical debt. There is so much and it is causing so much harm, the inclination is to try and fix it all at once. But nothing could be more detrimental from a business perspective. As you would handle anything on your backlog, prioritize it and systematically attack it.
Invest in Test Automation
I have often heard the notion that a value proposition of building solid test automation is that it provides a safety net so the team can courageously refactor. The point is, if there is little to no test automation, teams are reluctant-to-fearful to refactor because of side effects and how hard it is to detect (test for) them. I have found this to be incredibly true.
So a part of any refactoring effort should be focused on building test automation coverage. The two efforts strategically go hand-in-hand.
Find Release Tempo Opportunities
Most agile teams today have multiple tempos: sprint tempo, release or release train tempo, and calendar or external release tempo. You want to think about your various tempos and perhaps find opportunities within them for a focus on technical debt and refactoring. For example:
Many SaaS product companies have downtime periods in the calendar year when they do not necessarily want to release new code to their clients. At the email marketing firm, our time was over the Christmas holidays. From November to December each year we needed to keep releases to a minimum while our customers focused on holiday revenue. Given that, we would plan Refactoring Sprints & Releases over that period. Sometimes we focused on product code, for example, broad-brush defect repairs and component or feature refactoring. Another season we worked on our continuous deployment capabilities–focusing on scripting, tools, and deployment automation.
It was a great way for us to make investments and not disrupt our Product Roadmap plans.
Make it an Ongoing Investment
And the final strategic point is making it clear to everyone that technical debt and refactoring are an ongoing challenge and investment. They will not go away on their own. Even if you are implementing a greenfield project, you will be surprised how quickly you gain refactoring debt. It is driven by the nature of software–the customer needs change, technologies evolve and change, and teams change. In other words, change happens, so simply factor it into your strategic plans, roadmaps, and ongoing product backlogs.
The sub-title for this article was: it’s not a choice, it’s a responsibility. I hope the introductory story helped to crystalize that point. But I would like to emphasize it even more now.
Stakeholders will rarely tell you where and when to refactor. In fact, they typically hate the notion of refactoring, infrastructural investment, ongoing maintenance, etc. Instead they usually push their teams toward more and more new features. This pressure is organizational and will seep into the product organization, each Product Owner, and their teams. However, just because we are under pressure, it does not mean we need to abdicate our responsibilities and blindly succumb to it.
Rather, we need to activate our craftsmanship, our professionalism, our responsibility for doing good work and our courage to deliver that work. In other words, delivering software that will stand the test of time, exceed our customers’ expectations, and we can be proud of. All of that might sound too simplistic, but it is a core part of the principles behind the Agile methods.
Beyond words, each agile team and organization needs to make its technical debt (risks) and its refactoring efforts (investments) transparent. They need to become part of the everyday discussion that teams, managers, and senior leaders have as they transform their organizations towards agile execution. Striking a transparent balance should be the goal. I strongly suspect that everyone’s common sense and gut feelings will let him or her know when they have achieved it.
Stay agile my friends!
- Technical debt definition – http://en.wikipedia.org/wiki/Technical_debt
- Managing Software Debt by Chris Sterling is a wonderful book dedicated to all aspects of technical software debt.
- Here’s a link to an article/whitepaper I wrote on Technical Test Debt – a variant of technical debt that focuses on the testing and automation aspects – http://www.rgalen.com/presentation-download/articles-general-guidance/Managing%20Technical%20Test%20Debt.pdf
- A recent perspective by Henrik Kniberg – http://blog.crisp.se/2013/07/12/henrikkniberg/the-solution-to-technical-debt
- A fairly solid overview of technical debt with some solid references – http://queue.acm.org/detail.cfm?id=2168798
- Israel Gat of the Cutter Consortium has published several papers with his views on measuring and the ROI of Technical Debt. Searching for his works would be a good investment.