As an agency that works with many development teams and types of companies, it’s always fascinating to learn a little bit more about how different companies are using Ruby on Rails. Recently, we chatted with Casey O’Hara from PrintReleaf, a software platform that empowers businesses to certifiably reduce their environmental impact by automatically planting trees to offset their paper use.
With many companies undergoing Rails 5 updates, we asked Casey a few questions about how his development team handles these upgrades in their application and Gemfile.
It’s worth noting that PrintReleaf has a unique architecture for their Rails app that gives them some advantages when upgrading.
This was important to some of the questions we asked, so here was Casey’s description of the host app and advantages:
We make heavy use of Rails engines. What started as a single vanilla Rails app has evolved into a lightweight host app that serves as a mount point for several small, independent apps (Rails engines). The host app contains the models, services, and workers.
Unlike a typical Rails app, the host app doesn't have any controllers, views, or assets. It has a router, but no routes of its own; the host router is just a mount for the engines. The engines are located in /engines (there are currently 16: 'api', 'dashboard', 'marketing-site', etc.), each of them is a gem that is required by the host app's Gemfile. Each engine can be thought of as a separate, isolated "front end" containing its own router, controllers, views, layouts, and assets. Engines don't have their own models, all models belong to the host.
By separating our data/services layer from the individually isolated front-ends, everything is very loosely coupled, easy to test, and easy to change.
What gives your team confidence that your application(s) are running smoothly after you upgrade your Ruby and/or Rails versions?
We recently upgraded from Ruby 2.1 to 2.2.2 – not a huge jump but we took it seriously. A combination of things gives us confidence everything is operational. In development, the test suite. By design, our codebase is ~90% unit tests and ~10% very high-level integration tests to ensure everything is glued together correctly. If the suite is green, we feel pretty good about things.
In production, monitoring & analytics. After launch, we monitor for elevated error rates and keep an eye on health check metrics for our backend processes.
How often does your team review gem versions and consider updates?
Great question. We keep our Gemfile very, very lean. We are constantly removing unused dependencies and are very reluctant to add new gems.
The codebase is 5 years old and the Gemfile is only 80 lines long, 20 of which are our own private gems on GitHub.
Additionally, we lock the exact version for each specific gem, rarely do we use the ~> spermy operator. This way there are no surprises from Bundler; we manually control all gem version upgrades.
Generally, any time we 1) add a new gem; or 2) want to upgrade a gem, we will review and update everything related to that specific gem and often review all other gems at the same time.
For example, we recently upgraded from Sidekiq 4 to 5, so we also upgraded rspec-sidekiq, sidekiq-unique-jobs, etc. even though the older versions were compatible with Sidekiq 5. This keeps us using relatively recent versions for most gems.
Of all the Ruby on Rails upgrades that you've been part of, what was the most time-consuming version change?
A few years ago when we upgraded from Rails 3 to 4, we upgraded from Ruby 1.9.3 to 2.0 at the same time and ran into dependency issues in production around the asset pipeline. It took a while to find a compatible combination of Ubuntu, Ruby, and libv8.
What new features of Ruby on Rails v.5.x has your team been the most excited about using?
Honestly, we're more excited about upgrading other parts of the app (ex: LESS->Sass like I mentioned) but it makes sense to get on Rails 5 before upgrading other items to avoid accruing more technical debt.
When you perform updates, what is your team's strategy for collaborating on that?
We've found it best to have two developers work on the upgrade while the rest of the team continues on normal feature development. One dev is on the application layer (Rails), and the other on the infrastructure layer (Ruby + System).
We do a few days of research and spike some coding to get our heads around the problem before we start the upgrade. We usually aim to have the actual upgrade done in one working week, two weeks max, and time it so it doesn't coincide with any other important releases.
Working on a version branch, constantly rebasing the master branch to get the latest changes from master. It's the upgrade team's responsibility to take ownership of continually integrating during the upgrade – which isn't too bad because everyone is aware and conscious of the upgrade. Pull request, review, merge, deploy, done.
Depending on the size and setup of your Rails app, there are certain strategies that can make the upgrade process run smoothly. If you're reading this with a sense of dread that your app is falling behind, don't worry. We've put together a list of resources to help you get your app up to speed.
If you're in need of a bit more guidance or are looking to partner with an external team to handle upgrades so you can focus on new features, we can help there too. Find out more about our processes and schedule a call to chat about your application.