Years ago I had an epiphany that has stuck with me to this day. When I went away to grad school, I finally got an apartment of my own and thus had to cook my own meals (this was before microwave food become popular). Cooking was a messy process; my apartment did not come with a dishwasher; and I HATED to wash the dirty pots, pans and dishes, so I generally put cleanup off until later – much (days) later – until finally there was such a pile of dirty dishes that the sink was full, or I ran out of clean dishes, or guests were coming over. Then I was forced to deal with washing up a really big pile of dirty dishes, a big job that took a long time. Having a big pile of dirty dishes to deal with was a liability that hung over me.
At one point it occurred to me that if I washed every dirty dish immediately – concurrently with the cooking process – I would never have to face a big cleanup job. The cleanup process would be finished within seconds of the cooking process, and thus no backlog of dirty dishes would ever exist. And so cleaning up as I went has been my practice ever since. (But I admit that when I finally got a job, I made a point of getting an apartment with a dishwasher!)
And so for a development group, I strongly recommend the same policy: clean up your defects as you go, and NEVER let them pile up.
In a typical development cycle, the number of open defects keeps growing during the course of development, finally reaches a peak, and then starts a slow decline. In a true waterfall process where the testing doesn’t really get going until coding is done, the real ramp-up starts very late in the process. Fortunately, most development groups now start testing well before the feature complete milestone, and for groups using iterative development, the testing can start even sooner.
However, even when iterative development is used, there is danger that dirty dishes will pile up. This can happen if iterations are allowed to complete with open issues, especially if this happens repeatedly. So the best practice is that:
All code produced during an iteration should be complete at the end of the iteration – including all testing and fixes.
Said another way,
Each iteration should represent a potentially shippable version of the product.
Whoa, that sounds hard! you say. We don’t have time to do that – we need to get going on the next iteration. Besides QA is still busy testing code from an earlier iteration. And we’ll come back later and clean up any defects that they find. We need to finish cooking the meal, and we’ll wash the dishes later.
But allowing engineers to move forward before the last set of code is “done” (i.e. fully tested) is not a good idea for many reasons.
One of the really big problems with letting dirty dishes pile up is that you just can’t predict how long it will take to do the clean-up, thus putting schedules at risk (or quality, if you are forced to meet a schedule). Getting away from the dirty dish metaphor, until all planned quality verification is complete, you don’t know if there are any bigger issues lurking, and you run the risk of doing your next round of development on an unproven foundation, or greatly increasing the risk of the schedule impact caused by having to go back and do a lot of fixes on code that was supposedly “done”.
There can be a productivity impact to deal with the task switching necessary to put aside current work to deal with issues from “old” work.
And letting the engineers go on ahead effectively makes QA responsible for quality because it leaves them as the only ones standing between the code and the customer because everyone else is done with it unless QA tells them otherwise.
The best way of ensuring that you don’t have a quality problem is to never let one build up. Wash those dishes immediately, as you go.