A Simple Process for Upgrading Rails
This post walks through implementing an upgrade process rather than handling the specifics of any one or multiple version upgrades. It may seem simple but reduces risk during an upgrade. This is loosely tied to a Rails projects but could easily be applied to most framework-based applications.
1. Research
2. Plan
3. Implementation
4. Test & Iterate
Research & Planning
1. Put together a plan, notes, gather documentation and start reading
First thing is to do a little reading. The amount of pre-upgrade work you do should be driven by: (1) how large of a version jump you're making, (2) the size of your application and it's dependencies, (3) test coverage, and (4) perceived risk. For minor version jumps, you can probably skip most of these steps and be fine, but a major jump from 3.x
to 4.x
should be handled with care. With more dependencies, more research and planning. With lower test coverage and higher perceived risk, more research and planning. Hopefully you get the point: reduce risk.
Find all the documentation you need, including change-logs and guides: Railscasts, videos, blog posts, etc. I'd organize these with a set of upgrade notes or plan. I'd start off by reading the Rails Upgrade Guide to get a high-level sense of changes for the version you are upgrading to. As I mentioned previously, this is about implementing an upgrade process, not going into the specifics of any one version upgrade.
2. Find some tools, add to tool-belt and profit
Find anything that might aid in your upgrade process. For example, there is also a gem called rails4_upgrade
that will do a couple handy things including a gem compatibility check. bundler-audit
also has a couple handy tools.
Gems Mentioned:
3. Determine risk
If you don't already use them, static code analyzers like simplecov
or a service like CodeClimate are great for helping determine test coverage. Read the reports and you'll get a better sense of potential risk. rubocop
could also help you determine areas of heavy complexity.
Also, now is also a good time to add any error notifications services like exception_notification
and process monitoring if you don't already have them.
Gems Mentioned:
4. Increase automated test coverage. Only think green, like St. Patrick's Day
Now we know our risk, now would be a good time to fix up your test suite. If you have any broken tests, fix them. If you decide to add tests (never a bad decision), prioritize the ones you write. Here a few ways you might consider prioritizing by:
- Highest area of risk (this could be specific to the upgrade or just in general)
- Business critical or revenue generating functionality
- Lowest area of test coverage
This should go without saying, but make sure your tests all pass as any existing failures won't be as helpful once you start the upgrade.
5. Determine your plan of attack. Document testing, branching and deployment strategies
- Branching: You'll certainly want to work on a new branch... don't push to master. If you're doing several version upgrades one at a time, you might want each version on it's own branch. I.e., if you are going from 3.2 -> 4.2, consider doing 4.0, 4.1 and 4.2 on separate branches. Also consider large functional areas on separate branches or dependencies on different branches as well. This also depends on several other factors including the number of collaborators you'll have and when you will deploy each upgrade.
- Deployment & Testing: Depending on available resources and risk, you might want to spin-up a new instance for your upgrade branch, rather than deploying to an existing test instance. This would make it easier if there are any bug-fixes or features that need go into production before the upgrade is finished. No matter what path you choose, you, your colleagues, QA, other developers, business-stakeholders, your mother, some guy off the street - whoever, someone needs a way to test your upgraded app, and not in production.
- If there are multiple people working on the upgrade, you should have your upgrade plan mapped out and discussed with your team before actually going through the upgrade process. Assign responsibility and make sure everyone knows their role.
Final word of note, know that something will brake during your upgrade. The only question is what. If you're followed these steps and have all of this in place, you're reducing your risk significantly.
The Upgrade (Dun dun dun)
6. Work against a new rails app of the same version you are upgrading to
Compare a freshly installed version of that rails version to the one you are upgrading to. This helps.
7. Upgrade any broken gems and have a process for handling those upgrades. Drink a lot of coffee
Braking changes are a PITA. You should know if there are any coming from your research and have a way to handle them.
8. Read and understand what the deprecation warnings mean, aka RTFM
Yes, you need to read them. Figure out what they mean if they are important to you and if they will affect your upgrade path at all. ack
, grep
and Command + f
will come in handy here to know the extent of your problem:
DEPRECATION WARNING: This dynamic method is deprecated. Please use e.g. Post.find_or_initialize_by(name: 'foo') instead.
Testing
9. Run your specs (duh), and triple check the high risk areas you identified in research
Hopefully you wrote down the high risk areas you identified
10. Clone a fresh copy of your newly-upgraded app and try to set it up
Clone a copy of your upgraded app and see if you can re-install it from scratch. You'll probably find some bugs here.
11. Crawl your site looking for server errors or broken links
You can do this locally or against a deployed test branch. Integrity or Scrutiny are a couple good tools for link checking.
12. Have your stakeholders manually test everything before going into production
This includes you...