We've had an extensive discussion on this at my workplace, and the way we finally settled on was pushing code updates (including modules and themes) from development to staging to production. We're using Subversion for this, and it's working well so far.
What's particularly important is that you automate a process for pushing the database back from production, so that your developers can keep their copies of the database as close to production as possible. In a mission-critical environment, you want to be absolutely certain a module update isn't going to hose your database. The process we use is as follows:
- Install a module on the development server.
- Take note of whatever changes and updates were necessary. If there are any hitches, revert and do again until you have a solid, error-free process.
- Test your changes! Repeat your testing process as a normal, logged-in user, and again as an anonymous user.
- If the update process involved anything other than running update.php, then write a script to do it.
- Copy the production database to your staging server, and perform the same steps immediately. If it fails, diagnose the failure and return to step 1. Otherwise, continue.
- Test your changes!
- BACK UP YOUR PRODUCTION DATABASE and TAKE NOTE OF THE REVISION YOU HAVE CHECKED OUT FROM SVN.
- Put your production Drupal in maintenance mode, run "svn update" on your production tree, and go through your update process.
- Take Drupal out of maintenance mode and test everything (as admin, regular user, and anonymous)
And that's it. One thing you can never really expect for a community framework such as Drupal is to be able to move your database from testing to production after you go live. From then on, all database moves are from production to testing, which complicates the deployment process somewhat. Be careful! :)