When the application was put into production the original team split up and the developers was put on different projects. Most of the new projects was build on the same foundation and a lot of the experience could be reused. Those projects was much smaller and we did figure that we could build them in parallel instead of keeping the team and building them one after the other. Looking back I'm not sure this was the right decision and will never know. Anyway, we had to support the old application to fix bugs and add features on request.
Our customer wanted a few new features after the application went into production. With all the automated tests we could be quite confident that adding features would not break the application. We added new filtering and sorting functions, added feed forward for the filters and new fields for a few lists on web pages.
Yes, we did have one or two minor bugs, and one that really did make us reflect on our testing methods.
The bug removed a lot of data our customer had entered, as you can imagine this is not what they expected. Also, the first time it happened we could not believe it, as it was impossible for us to replicate. Until it happened a few times again. We did have unit test and automated acceptance test for the scenario and were confident the bug would have been trapped, that obviously was not true.
So, what was the case? We have three buttons, one "yes" and one "no" and one "regret". When clicking "yes" or "no" the "yes" and "no" buttons are hidden and the "regret" button is shown. Clicking the "regret" button restores the state so you can click "yes" or "no" again. A quite simple scenario, right?
Well, opening another browser, clicking the "yes" button and switch back to your first browser you still can click the "yes" or "no" button as that page has not been reloaded. Our backend logic is built to always allow you to click the "no" button, and that is correct in this case. Clicking the "no" button (from the first browser session) while actually being in the regret state made a call to a function that should never been called. This function was an update statement that updated more records than it should. We later found that due to a refactoring a parameter was removed from a SQL statement and never put back. Our unit tests tested the function with correct parameters but only using one record. This was a mistake, the test should have made the same test with more than one record.
But, while one of the bugs where severe there have been so few bugs that the effort put down into testing have payed off, a lot!
From all the stuff I've learnt from this project I see Pair Programming and Unit Testing as two of the most important lessons as a developer. There are a lot of other practices that is good, but may fall in the category of project management.
So, next up is to convince others that Pair Programming and Unit Testing is really great stuff.