RailsConf 2017

Upgrading a big application to Rails 5

Upgrading a big application to Rails 5

by Rafael França

In this presentation from RailsConf 2017, Rafael França discusses the journey and strategies involved in upgrading a large monolithic Rails application—specifically Shopify—from its previous versions to Rails 5. Francia outlines the challenges faced along the way, as well as the solutions implemented, emphasizing lessons learned for both the company and the Ruby on Rails community.

Key Points Discussed:
- Timeline of Rails and Shopify Development: Shopify's codebase, having started around the same time as Rails itself in 2004, has undergone several upgrades in close agreement with Rails releases. For instance, the upgrade to Rails 5 took about a year from its initial start until deployment, highlighting the scale and coordination necessary in such a large application.
- Complexity of Upgrading: The transition involved creating new branch strategies and maintaining code functionality across two versions of Rails simultaneously. A significant point made was the complexity of needing to handle code that operate under both Rails 4 and Rails 5, which was managed through conditional configurations in shared machine files.
- Key Challenges Encountered: The upgrade process was not without complications. Major issues included managing deprecations such as protected attributes transitioning to strong parameters, which required code adjustments to ensure secure and smooth data handling.
- Testing and Continuous Integration: France emphasized the importance of establishing a parallel Continuous Integration system that would validate the application behavior under both Rails versions. This practice allowed the identification and fixing of bugs collaboratively with other developers while ensuring stability.
- Community Contributions: França highlighted the role of contributing back to the community, particularly when some dependencies required updates to work with Rails 5, demonstrating a cycle of giving back to the framework that underpins the Shopify application.
- Future Plans and Considerations: Moving forward, Francia noted the desire for Shopify to maintain a consistent upgrade path, ensuring it remains on the latest versions of Rails to avoid the technical debt that stems from outdated code. This proactive approach seeks to foster a culture within the company where everyone contributes to keeping the application state-of-the-art.

In conclusion, the upgrade of Shopify to Rails 5 serves as a valuable case study for large Rails applications, demonstrating that while the upgrade process can be complex and challenging, strategic planning, community engagement, and an emphasis on testing can lead to a successful transition.

00:00:12.049 I'm here to talk about the history of upgrading a big Rails application to the latest version. This is a story of how Shopify managed to upgrade our monolithic Rails application to production. First, let me introduce myself. I am Rafael França, and you can find me on Twitter and GitHub as @rafaelfranca. I am a member of the Rails core team and work for Shopify as a developer. You may also know me because at every Rails conference, you'll see me in the Rails committee so I am also self-proclaimed as the Rails maintainer.
00:01:02.460 This talk is about how Shopify upgraded its application to a new version of Rails. Specifically, we started looking at Rails 5 because Shopify began around the same time as Rails itself. The initial commit of the Shopify codebase was in 2004, shortly before the first release of Rails. This means we’ve been using the same codebase for about 13 years.
00:01:40.920 As the timeline shows, Shopify follows the Rails releases very closely. For instance, after the release of Rails 2.0, Shopify upgraded shortly after. The same goes for Rails 3.0, but for Rails 4, it took us a bit longer to upgrade. We took about a year to upgrade to Rails 3.2 and maintained Rails 2.1 in the meantime because it was still stable for our application.
00:02:56.550 When it was time to upgrade to Rails 5, we started the process soon after its release in 2016. However, we only finished the upgrade by 2017. It took almost a full year to upgrade Shopify to Rails 5.0 from the previous version. Shopify is quite a large application—it’s the largest Rails application in production today, with over 374,000 lines of code. This number doesn’t even include any kind of stylesheet or JavaScript.
00:03:39.720 We also have more than 2,000 classes within our codebase, which contributes to a significant amount of complexity. Our test coverage is about 1.3 lines of tests for every line of code. It's important to note that Rails 5.1 is going to be a challenge, as we want to ensure our application continues to run smoothly.
00:04:45.430 So how do you upgrade a large application to Rails 5? In a straightforward situation, you would create a new branch and make all changes necessary to bring the application up to date. However, that's not our case. Shopify is a massive application, and we have hundreds of developers working on the same codebase every single day.
00:05:06.940 Upgrading to the latest Rails version while keeping everything functioning correctly is very difficult due to conflicts that may arise from code changes or the introduction of new bugs with every commit. We needed a strategy to utilize the same codebase with two different versions of Rails.
00:05:44.319 In our case, the best solution was to utilize a shared Gemfile. This approach allows us to run the same code with two different versions of Rails in both development and production environments. Implementing this solution is not overly complicated; it involves creating two different Gemfiles and using environment variables to manage dependencies.
00:06:49.360 We used conditionals in the Gemfile to determine which Rails version to use based on the current environment. This approach maintains the possibility of upgrades without the complications of trying to track changes across multiple files.
00:07:43.229 Eventually, we faced challenges with our testing setup. To get our tests to work correctly with both versions of Rails, we had to create a parallel Continuous Integration (CI) system that operated with Rails 4 and Rails 5 simultaneously. This way, we could ensure all changes were compatible.
00:08:45.780 During the upgrade, we encountered many dependency issues. It was essential that all dependencies worked with both Rails versions. Some dependencies required significant updates, which took time. One of our notable examples was upgrading the chain action page XML parser, which resulted in a more simplified codebase.
00:10:01.019 After upgrading the dependencies, the next task was fixing the numerous tests that had broken as a result of the upgrade. Our testing suite had thousands of failures. To manage this, we created a systematic process to address each failure.
00:11:55.830 One of the most significant challenges we faced during this process was around protected attributes in Rails controllers. The older way of handling these attributes changed significantly with Rails 5, requiring us to revisit how we managed model updating.
00:12:42.510 We had to ensure that sensitive fields such as user ID and passwords were only accessible when specifically allowed under certain conditions. This required adding a new method for attribute accessibility.
00:14:05.990 Another big change led to issues with working on controller tests, as the behavior of strong parameters changed between Rails 4 and 5. We had to update all our tests to ensure they were operating with the correct setup.
00:18:22.480 When we encountered issues with parameter handling, we found ourselves needing to upgrade our systems continuously. This upgrade process highlighted the importance of adapting our application to fit the changes in Rails.
00:19:58.199 The Rails 5 upgrade required significant code refactoring. Parameters were no longer inherited by default, which posed a challenge since many developers relied on this behavior.
00:21:50.219 As we wrapped up the upgrade and transitioned the application into production, we ensured that deprecated code was removed and compatibility layers were created to support the legacy features.
00:23:37.100 The objective moving forward is to keep Shopify aligned with the latest Rails versions while ensuring backward compatibility and minimal disruption to our users.
00:30:27.859 If anyone has further questions about our upgrade process or the changes made, I'm here to discuss and share insights. Thank you!