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:

  1. Highest area of risk (this could be specific to the upgrade or just in general)
  2. Business critical or revenue generating functionality
  3. 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.

![Know Your Role](/content/images/2016/06/know-your-role.jpg)

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.

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...

13. Everything works (like it should). Grab a beer and celebrate
![Celebrate](/content/images/2016/06/aww-yiss.gif)