Some Thoughts after a Major Ruby on Rails Upgrade
A few thoughts from recent work upgrading a Ruby on Rails app
For the past few weeks, I've been upgrading an older, fairly large Ruby on Rails app from Rails 5.2 to Rails 7.1 and from Ruby 2.7 to Ruby 3.3. During this time, I have also made the switch from Webpacker to Vite for asset bundling and made various JS and CSS upgrades to go along with that change. Here are a few takeaways from the experience.
Upgrade Regularly #
First, I know I am probably preaching to the choir with this one, but just upgrading your tech as you go and whenever you can is great. It prevents you from being in the position that I was in–having to make such a big jump all in one go. It also makes sure you keep getting security upgrades, and more security is never a bad thing. If you are up for it, you can even automate the process like GitHub does for their Rails upgrades or by using something like Dependabot for notifying you on when to upgrade dependencies.
Commit Often #
This is good advice for any project, but I think it is specifically good when working through issues that arise from upgrading. Whenever I have done a larger upgrade, there’s always at least one tricky issue that takes time to diagnose. This leads to me experimenting and trying a few different things before I figure out the actual fix. Committing often allows me to reset back away from these false paths whenever I decide to go down a new one. But I could also commit these false paths if I'm stuck, store them away in a separate branch, and come back to them later if I feel like an approach is worth a second look.
Leave Code Comments #
If you have a particularly confusing piece of code where its purpose or function is unclear, leave a comment. This is another piece of advice that is relevant at any time, but I found those comments to be extra helpful during this latest round of upgrades. There were several instances of code that had not been touched in years (and never touched by me) causing errors after upgrading the underlying tech. Some of these were well commented, which made it much easier to understand their purpose and decide how to fix them—or even whether to keep them. On the flip side, there were some pieces of code that were not well documented, which made fixing the errors much harder.
Avoid Fancy Code #
As somewhat of an alternative to the code comments, you can also just avoid fancier code. Try seeing if any code that is fairly complex can be simplified into something a bit easier to understand. Also, you want to avoid calling any private APIs that might change out from under you during your upgrade process which can lead to all sorts of weird bugs and behavior. I'm not saying do this completely in place of relevant comments, but simplifying where you can will somewhat cut back the need for them.
Be Selective with Dependencies #
When upgrading a massive Rails app and the Javascript associated with said app, you are often going to have to upgrade some of your dependencies as well. The more of these you have to upgrade, the higher chance you have of breaking something, so it is important to be selective when choosing these dependencies. During these upgrades, I ran into several issues caused by a dependency that really was not doing much for us in the grand scheme of things, but was causing more than its fair share of issues. If you want to read more about how to go about choosing dependencies, feel free to reference my colleague Sol's article on the subject.
The End #
I don't think these insights are particularly original or profound, but hopefully they give you something to think about as you make major upgrades on your own app or as you think ahead to future upgrades.