A quote by Martin Fowler (I think it's from Refactoring: improving the design of existing code), discussing the quality of software divides it into internal and external quality:
Internal quality is about the design of the software. This is purely the interest of development. If Internal quality starts falling the system will be less amenable to change in the future. [...] You need to be very careful about letting internal quality slip.
External Quality is the fitness for purpose of the software. It's most obvious measure is the Functional Tests, and some measure of the bugs that are still loose when the product is released.
-- Martin Fowler
Literature about managing software projects and code quality often states that internal quality of a product is never negotiable, no matter how urgently a feature for external quality needs implementation. Even the principles behind the Agile Manifesto say: "Continuous attention to technical excellence and good design enhances agility."
Since internal quality cannot be lowered, one should rather not implement the feature than compromise the code-quality. At the end of any iteration of development, the code should be clean, readable, well tested and versatile enough to accommodate changes in the future. Unfortunately, reality doesn't work that way. To this the principles behind the Agile Manifesto say: "Working software is the primary measure of progress. " So often enough we developers need to hurry up and hack in a crucial feature for a demo with a customer in last minute or during a crunch before a presentation at a conference or even a release. How often we heard the sentence: "Just make it work, we can clean up and maybe patch the software later", knowing well that "later" might as well be never. So we hack away furiously, violating our own code conventions and ease our conscience by adding a few "///@todo clean up... " into the code and getting unhappier the longer it takes.
Crunch and Refactor
So instead of fighting this contradiction and arguing that "It's not how it was planned", try to plan it. I call this method the "Crunch and Refactor" method, which consists of four simple rules. Crunch time is the time you spend quickly hacking new features into the project while refactor time is the time when you clean it up and advance the said features
- The crunch time has to be defined in advance as a fixed time span
- refactor time follows immediately after the crunch
- refactor time is double the crunch time
- Crunch time cannot happen right after refactor time
By defining the crunch-times in advance your team can plan their free time (or the lack of it) accordingly and by setting a hard deadline one knows that the stressful time is limited. Being under constant high pressure without being able to see an end of it, is a quite sure way to a burn out, and seeing an end to it will help preventing it.
So your stressful deadline is past, you had your release party and hopefully impressed the world with your product, but now it's time to clean up the kludges you left behind in the process. By starting with cleaning up right after the end of the crunch, it's ensured that all those hacks are still present in your teams mind, as well that you don't fall into the "we clean up later" trap.
By giving your team double the time to clean up as you spent crunching, the importance placed on good quality software is signaled not just to the developers, but also to the management outside the team. The other benefit of it is, that since the batteries of a team are probably nearly drained after a stressful crunch, taking a pace that is more relaxed afterwards will help them recover their focus faster.
The reason why you're not allowed to crunch right after refactoring is to avoid a alternating between the two phases, as you might want to get back to a normal development-cycle between two releases. The third rule also helps enforcing the first rule, by forcing the planing ahead.
Of course "Crunch and Refactor" only works if you keep the times relatively short, it is no use to hack away without any decent engineering for six months and then trying to spend a year to clean it up afterwards. On the other hand defining every stressful day as a crunch-time and then spending two days relaxing and cleaning up is not the way to go either, as this is kind of a normal fluctuation during work. Anything from one-week crunches up to a month seem reasonable.
A good idea for it is to lay this methodology over an agile methods like scrum, where you can define a sprint as crunch-sprint and the next two sprints as refactor-sprints, this separating those two steps even more clearly.