Too many times I see this process for upgrading frameworks:
- Halt all new feature development
- Upgrade framework
- Test manually
- Keep testing and fixing
- Keep testing and fixing
- Deploy to a pre-production environment... and keep testing and fixing
- Repeat for each environment
- Deploy to production
- Pray to whatever deity you believe in
- Keep testing and fixing
Step 2 should actually be step #3. Step 1 should be entirely unnecessary. If you need to do step #1, you are doing it wrong.
Step 1 should be start with unit and automated test coverage.
I was part of an agile team that not only was able to do a non compatible framework upgrade, but also a non compatible upgrade to the language itself. It was a large Ruby on Rails application upgrading to Ruby 1.9. So basically every framework, library and dependency we had was also upgraded or replaced.
In 4 weeks. In 4 environments, including production. And we delivered 4 major new features as well.
This is not a way to say "Ruby is better!" rather, it is a testament to the amount of unit and automated test coverage the application had. We had 1,200+ unit tests, and around 600 cucumber tests. It is also a testament to a tightly knit team with great communication.
So, my amended list of steps for upgrading a framework, or major piece of your software infrastructure:
Write lots of unit tests. Refactor code if necessary so you can write unit tests for the core logic of your application
Create automated functional tests. Not everything can be tested with a unit test, but a full functional test through the UI is the next best thing. Write lots of these.
Repeat steps 1 and 2.
Upgrade the framework.
Get the unit tests to pass.
Get the functional tests to pass.
Keep track of the breaking changes you need to make. E-mail your team about these changes and how they can fix work in progress.
Team code review. Have them ask questions. Answer them in great detail.
Check code in, and make sure your continuous integration build is passing.
Assist teammates with merges and bug fixing for work in progress.
Deploy to a pre-production environment for manual testing. Have a manual test plan already in place.
Deploy to the next pre-production environment, followed with some more testing.
Deploy to production.
The key difference between the two approaches is when you work out the kinks. With approach #1 you encounter most issues during manual testing. With approach #2 you encounter them during development, where they are easier to track down and fix.