Hardening Sprints are one of the most common kinds of Scrum Anti-Patterns: ways of addressing recurring problems that seem like effective solutions at the time but in fact hamper productivity or create more problems later on. Here we introduce why they are used, why they are not an effective design pattern, and how you can create more effective solutions.
In software development work, a design pattern is a description of a solution to a recurring problem. It outlines the elements that are necessary to solve the problem, including context and the consequences of certain actions, without prompting the reader to solve the problem a specific way, leaving them with the agency to write code as they see fit. Patterns, when applied well and not overused, provide a guide to solving repetitive problems rapidly. A good pattern provides enough background information to help the reader appreciate where it is applicable, without declaring that is the best solution in all instances.
Scrum, Agile, and Kanban, in this sense, are sets of behavioural design patterns. In the Scrum Community, we have Scrum PLOP (Pattern Language of Programs) that documents known patterns of effective behaviour.
Unfortunately, we also regularly see recurring patterns of ineffective behaviour. These are called Anti-Patterns.
“An anti-pattern is just like a pattern, except that instead of a solution it gives something that looks superficially like a solution but isn’t one.” ~ Andrew Koenig
Scrum as an approach is already designed to deal with the unpredictable, without having to force exceptions. Whenever a team creates an exception, such as a special Sprint to solve a challenge, it creates an Anti-Pattern, which often results in a whole set of additional problems.
The following is an exploration one of the most common Anti-Patterns: the “Hardening Sprint.”
Anti-Pattern Name: Hardening Sprint
Aliases: Stabilization, Hangover, Release Sprint, or IP Iteration (Innovation and Planning Iteration in SAFe)
Scale: Team and across multiple teams
Related Anti-Patterns: Sprint 0, Separate Test Team; Component Teams; Technical Debt can be paid off later; Sprint Burndown Charts, Velocity is Important, ….
- Better Definition of “Done”
- Improve Engineering Practices
Teams new to Scrum often focus on getting as many User Stories finished as they can every Sprint. If they have good discipline, they write Unit Tests for their code. Once complete, they ship the feature off to their overburdened testers. In Sprint Review, the feature is accepted by the Product Owner. If defects are found, they’re added to the product backlog in a lower priority slot.
While this sounds fine on the surface, trouble may be brewing. If they finish User Stories to the Definition of “Done” but that definition still leaves some things to be dealt with later, eventually it’s going to catch up to them.
After five or six Sprints at this pace, they may elect to pause and have a “special” Sprint, or Hardening Sprint. They use this Sprint to do all of the work that they postponed in the working Sprints. The delayed work often includes tasks such as running a regression test suite, doing performance tests, and fixing defects. Usually, more defects are found than can be fixed. Once the Hardening Sprint is complete, the Product is released to Production.
While this is common practice, it’s not in the spirit of Scrum. Scrum is intended to help teams learn the rigour and discipline to ship working software at the end of every Sprint. Clearly, having a Hardening Sprint as part of the process allows the Team to avoid dealing with that challenge, and therefore becomes an anti-pattern.
Teams who have spent a long time working in a traditional fashion often elect for Hardening Sprints. This isn’t surprising since Hardening Sprints seem like a logical replacement for the testing and deployment phases that they’ve been used to. But that’s only because Teams new to Scrum haven’t yet felt the pain that is caused by these special Sprints, so they’re more likely to fall into the trap of thinking that they’re the solution to the difficult question of how to deliver working software at the end of every Sprint.
Hardening Sprints are the developers’ version of “We’ll fix it in post.” They tend to decrease the readability of the code base because people have a habit of delaying any tidy-up work until then. The messier the code is to read, the harder and more time-intensive it is to add new features or test existing ones. Many people call this Technical Debt. It doesn’t take long before the team needs to add more time into the Hardening Sprint to get the work fully tested.
Hardening Sprints have negative downstream consequences too. By delaying the release of a working product to the customer, we delay when they will pay us. Traditional or Waterfall approaches delay testing, writing documentation, etc. to the end of the process. When we delay work until a Hardening Sprint, we’re dragging a traditional approach into an Agile environment.
The use of Hardening Sprints leads to:
- A larger volume of untested code – Many forms of testing (regression, performance, usability, etc.) are postponed until the Hardening Sprint.
- Defects difficult to resolve – The longer we delay in fixing them, the harder they are to fix, both because the person who wrote them forgot their intention and code base will have evolved so we may be relying on the defective behaviour elsewhere.
- An increase in defects that are either not discovered or discovered later – The more time that passes between writing code and testing it, the harder the defects are to find. In many cases, because of the ever-growing complexity, the defects are never found.
- Delay for the customer – In real Scrum, the customer can use the Product Increment (aka Working Software) at the end of every Sprint. With Hardening Sprints, they get access only after the Hardening Sprint. If Hardening Sprints happen every 5-6 Sprints, that means at least 3 months without new software and real engagement.
- An increase in the complexity of the regression tests **eventually** requiring an increase in the time spent doing Hardening Sprints – As the code base grows, so do the number of test cases. Eventually, one Sprint isn’t enough to run them all (let alone fix the defects) so we schedule another Hardening Sprint.
- More difficult to tidy messes after they’re found because the code base is more fragile – Lacking good unit tests and automated acceptance tests, making changes becomes harder because we don’t know if we can trust that our change is good. Often we avoid making changes (e.g. refactoring) because the changes are “too risky.”
- Regression Test cases run by hand (or manually) being error-prone – We’re relying on people noticing mistakes in software that they have seen many times before. Even the most careful tester will miss things due to this form of repetition blindness, called the Observer-Expectancy Effect. Relying on people to do repetitive task work is error-prone and boring for the people.
If you wish to have maintainable software, then you must eliminate the Hardening Sprint. Large Scale Scrum hints at the problem by calling anything not truly done in the Sprint as “Undone Work”.
- A belief that teams need to work faster from the start
- Focus on increasing velocity, without first focusing on quality
- A “traditional phased” approach to Scrum
- A weak or non-existent definition of “Done”
- Lack of rigorous engineering practices
- A belief that multi-Team efforts require extra integration time before they’re ready to release
- SAFe  recommendation (called an IP Iteration)
- Improve Definition of “Done”
- Large Scale Scrum calls the difference between Potentially Shippable and Definition of Done “Undone Work”
- Improve Engineering Practices
Both of the above should result in the Team discovering Agile Test Engineering Practices such as Specification By Example/BDD/ATDD, etc.
- Slow down. Don’t focus on speed – instead, focus on quality. (Which should result in the team focus of learning. This should, in turn, discover Agile Test Engineering Practices.)
- Consider the Pattern: Good Housekeeping or Daily Clean Code
- Deliver working software at the end of every Sprint. (Which should refocus on Definition of “Done” and Agile Test Engineering Practices.)
- Consider Pattern: Teams that Finish Early Improve Faster
Realistically, there is only one solution to the challenge that Hardening Sprints represent: reduce the number of time-demanding things that get pushed forward to be a future problem. Most of the work that is delayed to a Hardening Sprint is comprised of pieces of work that are done manually. For example, many software teams have a suite of regressions tests that require a person to execute a series of steps in the software and check the results. That takes manhours, so to have the resources and capacity to run these tests every Sprint, we need to reduce the overall manual load.
To reduce the number of manual tasks, a team could:
- Take one or two test cases every Sprint and find ways to automate them. It is sometimes easier to automate in the area the team is already doing feature work. Caveat: the default approach to test automation – automate the GUI  and watch the results – is often not effective in the long run. However, effective test automation is beyond the scope of this blog entry.
- Slow down. Since automated testing will require new skills, the team needs to slow down and take time to learn. Too often it is assumed that team members will learn by osmosis.
- Prioritize fixing defects. Delaying the fix just increases the complexity of the eventual fix and the code base. If instead, the Product Owner puts defects at the top of the Product Backlog when they’re found, they’re also sending the team a clear message: focus on quality.
Related to defects are those messes (incorrectly called “Technical Debt”) in the code base that are below the level that the Product Owner can see. If they’re small (e.g. 15-30 minutes work) they should just be fixed right away. If they’re larger, they warrant a discussion with the team on how that section of the code can be improved as part of their ongoing work.
Teams that follow this approach well should not only eliminate their Hardening Sprint, but they should also be able to join the groups that do true Continuous Deployment/Delivery.
If done correctly, Teams will eventually wander into the realm of DevOps simply by getting more truly done every Sprint.
In Certified ScrumMaster training, when discussing the Definition of “Done”, I usually reveal my true feelings and call Hardening Sprints what they should be called: an abomination. Or a slightly gentler version: Hangover Sprints.