00:00:20.640
Today, we're going to discuss Ruby 1.9. While Ruby 1.9 is not new, I suspect that many of you with large production apps still haven't migrated. A year ago, New Relic was not running on Ruby 1.9 either. It was a challenge, but today we're here to show you how we accomplished it and how you might begin the transition yourself. It's crucial to understand that the patterns we discuss today are applicable not only to Ruby upgrades but also to Rails and other upgrades. It's time to upgrade to 2.0. I'm Nick from the site engineering team at New Relic.
00:01:11.920
I'm Ralph, and I work on the core app team at New Relic. We built the significant Rails app that we’ll be focusing on today, ensuring it runs smoothly in a production environment. The collaboration between our two teams, especially sharing resources and knowledge, was key during this process. The site engineering team is not isolated from development; although they often are, they are skilled Rubyists who understand Ruby. The development team is familiar with operational aspects, enabling us to overcome hurdles together.
00:01:36.400
As Kobe briefly introduced, New Relic offers application performance monitoring for various languages, including Ruby, Python, Java, and .NET. Our monitoring tools indicated that our app was slow, highlighting the need for significant improvements. Ralph and I contributed to this upgrade project, but we were not the only contributors; around 25 people worked on that app, and several teams, including the Ruby agent team and the site engineering team, were involved. Notably, four individuals played crucial roles: John Guyman, our spiritual leader Bill Kaiser, Jonathan Owens, and Andrew Bloomgarden. They're busy with hard work while we share our experiences here.
00:02:21.760
You may already be aware of the syntax changes, performance advantages, and other compelling reasons to upgrade to Ruby 1.9. Let's take a moment to encourage those who may still rely on Ruby 1.8 to think about making the switch. Is anyone still using Ruby 1.8? That's alright, but it's important to note that Ruby 1.9 has been available for a long time and is fully supported. Meanwhile, support for Ruby 1.8 is coming to an end, and if you’re using it in production, you might be relying on Ruby Enterprise Edition due to performance needs. This version is no longer actively supported, and users submitting bugs feel the impact of that lack of attention. So, things are shifting towards an inevitable end of life for Ruby 1.8.
00:03:05.920
This data from New Relic illustrates the situation: many Ruby users are transitioning to Ruby 1.9 or even Ruby 2.0. However, substantial numbers of applications still run on Ruby 1.8, indicating that there's still work to be done. Let’s remind ourselves of the reasons holding people back from upgrading to Ruby 1.9. Common objections include concerns about the size of their legacy applications and fear of the difficulties involved in upgrading while still maintaining ongoing development. Our app, too, is sizable and has legacy elements; for reference, our first commit was made in July 2007 with Rails version 1.2.3. Since then, we have consistently upgraded and are now running on Rails 3.0.
00:04:05.600
At the time we switched to Ruby 1.9, our codebase included around seventy thousand lines of code and nearly sixty thousand lines of tests. We were running Ruby Enterprise Edition, which had become increasingly outdated. Our main worry wasn't just about the size of the codebase; we were concerned about halting ongoing development. Shopify’s migration, for instance, involved dedicating multiple engineers who couldn’t ship features during that time, a scenario we sought to avoid. Initially, we thought about splitting our app to make it simpler to upgrade, but we mostly ended up just talking without significant action.
00:05:10.560
Eventually, we concluded that we would have to take the plunge and attempt the upgrade all at once, freezing our ongoing work to focus on the transition. John Guyman, who is here today, initiated a project aiming to convert the codebase in just one day — albeit, it didn't go as smoothly as planned. After several attempts to create branches, we found that merging back changes was extremely painful. Our branch needed constant updates against master, incorporating its own set of tests and changes that had been made. This only highlighted how difficult it was to maintain that approach.
00:06:09.120
With this realization, we acknowledged that we needed a continuous deployment standard: everything stays on master. By utilizing feature flags, we could continuously integrate any changes into master at all times, regardless of whether they were live or not. Thus, we established a system where we had a branch for Ruby 1.9 and a parallel CI job to monitor its health. We employed Jenkins to run two jobs simultaneously: one for Ruby 1.8 and another for Ruby 1.9, with early results from the Ruby 1.9 job being quite enlightening, indicating problems even before we formally completed the upgrade.
00:07:18.080
The next step was to work on smaller components within the application that would allow us to ease into the upgrade. However, a significant portion of our workload was focused on ensuring our foundational systems were in order. A critical task involved ensuring that our app could effectively run multiple Ruby versions side by side. Initially, we needed to upgrade our Rails version to at least 2.3 to ensure compatibility with Ruby 1.9. All the while, ensuring security was another important consideration to improve our application's stability.
00:08:18.560
Additionally, we needed an infrastructure in place for switching Ruby versions. Thankfully, the community provided excellent tools for this, particularly rbenv, which we integrated into our workstations, CI systems, staging, and production environments. As we migrated our production environment to use rbenv for managing Ruby versions, it enabled us to switch back and forth seamlessly across our stack. Crucially, the introduction of Bundler significantly aided in managing the Ruby gems, ensuring compatibility between Ruby 1.8 and Ruby 1.9.
00:09:05.680
To ensure a successful rollout, we had to maintain solid test coverage that would shield us from unforeseen complications following changes. Prior to the upgrade, we had 76% test coverage, which was better than 50%, but we quickly uncovered gaps in our testing framework, exposing areas in need of improvement. With that understanding, we pushed forward into the more challenging aspects of ensuring our complete test suite was operational under Ruby 1.9.
00:10:07.280
A significant challenge was handling third-party gems and plugins that were incompatible with Ruby 1.9. Specifically, we had to replace Ruport and Mongrel, which were not compatible with the newer Ruby version. Instead, we transitioned to Unicorn. We worked through all these changes on our master environment, pushing everything to production incrementally. This approach helped us slowly shed our dependencies on Ruby 1.8's environment while we concurrently ran on Ruby 1.9.
00:11:02.400
One of the biggest time investments during this transition was addressing test failures. The initial work began in March, and we reached completion by early September 2011. This didn’t include the time we spent originally resisting the need for the upgrade. We kept the project moving without halting everything else in the pipeline. Over time, new commits were consistently being checked against Ruby 1.9 compatibility, ultimately preventing further regressions.
00:12:09.840
We learned that Ruby 1.9 introduced several behavioral changes—small in isolation but significant in a larger application context. This metric meant we needed to carefully check for compatibility while testing. One of the biggest hurdles was sorting out complex syntax and structural issues we had throughout our codebase. By applying various strategies, we were able to tackle these nuanced changes as they arose.
00:13:00.000
As we delved into our upgrade project, we began encountering peculiar issues—like load paths suddenly not functioning as expected under Ruby 1.9. Each of our support scripts and background processes broke down as we moved along the upgrade path. We spent considerable efforts rectifying these issues as they appeared across our extensive codebase. We ensured our code remained flexible, accommodating both Ruby versions during the rollout, while keeping the application as stable as possible.
00:14:05.680
In addition to focusing on gem compatibility and making the necessary syntax changes, we were also mindful of employing best practices throughout our upgrade process. For instance, the introduction of ordered hashes in Ruby 1.9 forced us to reevaluate how we were handling collections throughout the application. Countless smaller bugs emerged based on our app's previous dependencies on the behavior of earlier Ruby versions.
00:15:10.800
Ultimately, after ensuring our codebase was clean and functional across versions, we rolled into the enhanced performance metrics. We eventually saw a dramatic uptick in performance—a testament to our effort and patience during the upgrade journey. The improvements in garbage collection times reflected a 75% reduction in workload, alongside a steep drop in CPU usage on our app servers. This level of optimization contributed significantly to the efficiency and speed that user experience underwent.
00:16:24.800
Reflecting on the entire process, we realized we learned valuable lessons along the way. Among them was the critical importance of collaboration and consistent communication across both teams involved in the upgrade. These experiences positioned us to apply similar practices for future upgrades as we look ahead to upgrading to Rails and Ruby 2.0.
00:17:39.200
Both Andrew and Julian are team members who contributed to the Rails 3 upgrade and faced their own unique challenges. They’ll be discussing their methodologies at RailsConf this year, so keep an eye out for their sessions. As we continuously work to enhance our applications, hiring is also something we prioritize within the engineering teams—so if you're interested, we'd love to chat.
00:18:33.760
To conclude, we appreciate your attention and look forward to any questions you may have regarding our upgrade experiences or broader discussions about Ruby and Rails. Our journey towards Ruby 1.9 might have had its challenges, but the outcomes significantly improved our application, and we hope to encourage others to follow this transformative path.
00:19:26.640
Thank you very much!