Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Ten Years of Rails Upgrades

Ten Years of Rails Upgrades

Presented at RailsConf 2018 in Pittsburgh, PA.

Upgrading Rails can go from easy-to-hard quickly. If you've struggled to upgrade to a new version of Rails, you're not alone. And yet, with useful deprecation warnings and extensive beta periods, Rails has never made it easier to upgrade. So what makes it hard?

By looking at the past ten years of Rails upgrades at Clio (and other notable apps), let's see what we can learn. Gain insight into the tradeoffs between different timelines and approaches and learn practical ways to keep your app up-to-date.

Jordan Raine

April 19, 2018
Tweet

More Decks by Jordan Raine

Other Decks in Programming

Transcript

  1. Jordan Raine (@jnraine) I’m a Rails developer at Clio From

    Vancouver, BC ! " # Ten Years of Rails Upgrades
  2. $ Tiny Co. % Big Inc. 1. Gems Few Many

    2. Code changes Few Many 3. Test Few failures Won’t even run 4. Deploy Easy Terrifying
  3. $ Tiny Co. % Big Inc. 1. Gems ✅ ✅

    2. Code changes ✅ ✅ 3. Test ✅ ✅ 4. Deploy ✅ ✅
  4. 2010 2011 2012 2013 2014 2015 2009 2008 2007 2016

    2017 2018 2.0 3.0 3.1 3.2 2.1 2.2 2.3 2.0 2.1 2.2 2.3 3.0 3.1 3.2 4.0 4.2 4.1 5.0 5.1 5.2 4.0 4.1 4.2
  5. 2010 2011 2012 2013 2014 2015 2009 2008 2007 2016

    2017 2018 2.0 3.0 3.1 3.2 2.1 2.2 2.3 2.0 2.1 2.2 2.3 3.0 3.1 3.2 4.0 4.2 4.1 5.0 5.1 5.2 4.0 4.1 4.2
  6. 2010 2011 2012 2013 2014 2015 2009 2008 2007 2016

    2017 2018 2.0 3.0 3.1 3.2 2.1 2.2 2.3 2.0 2.1 2.2 2.3 3.0 3.1 3.2 4.0 4.2 4.1 5.0 5.1 5.2 4.0 4.1 4.2
  7. The Excel team’s ruggedly independent mentality also meant that they

    always shipped on time [and] their code was of uniformly high quality. Joel On Software https://www.joelonsoftware.com/2001/10/14/in-defense-of-not-invented-here-syndrome/ “ ”
  8. 2010 2011 2012 2013 2014 2015 2009 2008 2007 2016

    2017 2018 2.0 3.0 3.1 3.2 2.1 2.2 2.3 2.0 2.1 2.2 2.3 3.0 3.1 3.2 4.0 4.2 4.1 5.0 5.1 5.2 4.0 4.1 4.2 ( ( (
  9. $ bundle outdated Outdated gems included in the bundle: *

    actionmailer (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * actionpack (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * actionview (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * active_model_serializers (newest 0.10.7, installed 0.8.3, requested ~> 0.8.3) in groups "default" * activejob (newest 5.2.0, installed 5.1.4) * activemodel (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * activerecord (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default"
  10. actionmailer (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups

    "default" name newest version installed version requested version group
  11. $ bundle outdated bundle outdated Fetching gem metadata from https://rubygems.org/...............

    Fetching gem metadata from https://rubygems.org/.. Resolving dependencies........... Outdated gems included in the bundle: * actionmailer (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * actionpack (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * actionview (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * active_model_serializers (newest 0.10.7, installed 0.8.3, requested ~> 0.8.3) in groups "default" * activejob (newest 5.2.0, installed 5.1.4) * activemodel (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * activerecord (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * activesupport (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * addressable (newest 2.5.2, installed 2.5.1) * arel (newest 9.0.0, installed 8.0.0) * aws-partitions (newest 1.80.0, installed 1.24.0) * aws-sdk-core (newest 3.19.0, installed 3.6.0) * aws-sdk-kms (newest 1.5.0, installed 1.2.0) * aws-sdk-s3 (newest 1.9.0, installed 1.4.0) in groups "default" * barber (newest 0.12.0, installed 0.11.2) in groups "default" * better_errors (newest 2.4.0, installed 2.1.1) in groups "development" * bootsnap (newest 1.3.0, installed 1.1.8) in groups "default" * bullet (newest 5.7.5, installed 5.5.1) in groups "development" * byebug (newest 10.0.2, installed 9.0.6) in groups "test, development" * chunky_png (newest 1.3.10, installed 1.3.8) * crass (newest 1.0.4, installed 1.0.3) * ember-data-source (newest 3.0.2, installed 2.2.1) * ember-handlebars-template (newest 0.8.0, installed 0.7.5, requested = 0.7.5) in groups "default" * ember-rails (newest 0.21.0, installed 0.18.5, requested = 0.18.5) in groups "default" * ember-source (newest 2.18.2, installed 2.13.3, requested = 2.13.3) in groups "default" * erubi (newest 1.7.1, installed 1.6.1) * excon (newest 0.62.0, installed 0.56.0) in groups "default" * exifr (newest 1.3.3, installed 1.2.5) * fabrication (newest 2.20.1, installed 2.9.8, requested = 2.9.8) in groups "test, development" * faraday (newest 0.14.0, installed 0.11.0) * ffi (newest 1.9.23, installed 1.9.18) * globalid (newest 0.4.1, installed 0.4.0) * hashdiff (newest 0.3.7, installed 0.3.4) * hashie (newest 3.5.7, installed 3.5.5) * highline (newest 1.7.10, installed 1.7.8) in groups "default" * http_accept_language (newest 2.1.1, installed 2.0.5, requested ~> 2.0.5) in groups "default" * i18n (newest 1.0.0, installed 0.8.6) * in_threads (newest 1.5.0, installed 1.4.0) * jmespath (newest 1.4.0, installed 1.3.1) * jwt (newest 2.1.0, installed 1.5.6) * kgio (newest 2.11.2, installed 2.11.1) * lograge (newest 0.10.0, installed 0.7.1) in groups "default" * logstash-logger (newest 0.26.1, installed 0.25.1) in groups "default" * method_source (newest 0.9.0, installed 0.8.2) * mini_mime (newest 1.0.0, installed 0.1.3) in groups "default" * minitest (newest 5.11.3, installed 5.10.3) in groups "test" * mocha (newest 1.5.0, installed 1.2.1) in groups "test, development" * mock_redis (newest 0.18.0, installed 0.17.3) in groups "test, development" * oauth (newest 0.5.4, installed 0.5.1) * oauth2 (newest 1.4.0, installed 1.3.1) * oj (newest 3.5.1, installed 3.4.0) in groups "default" * omniauth (newest 1.8.1, installed 1.6.1) in groups "default" * omniauth-facebook (newest 5.0.0, installed 4.0.0) in groups "default" * omniauth-google-oauth2 (newest 0.5.3, installed 0.3.1) in groups "default" * omniauth-instagram (newest 1.3.0, installed 1.0.2) in groups "default" * omniauth-oauth2 (newest 1.5.0, installed 1.4.0) in groups "default" * omniauth-twitter (newest 1.4.0, installed 1.3.0) in groups "default" * parser (newest 2.5.1.0, installed 2.5.0.3) * pg (newest 1.0.0, installed 0.21.0, requested ~> 0.21.0) in groups "default" * progress (newest 3.4.0, installed 3.3.1) * pry (newest 0.11.3, installed 0.10.4) * pry-rails (newest 0.3.6, installed 0.3.4) in groups "default" * public_suffix (newest 3.0.2, installed 2.0.5) * puma (newest 3.11.4, installed 3.9.1) in groups "default" * r2 (newest 0.2.7, installed 0.2.6, requested ~> 0.2.5) in groups "default" * rack-openid (newest 1.4.2, installed 1.3.1) * rack-test (newest 1.0.0, installed 0.7.0) * railties (newest 5.2.0, installed 5.1.4, requested ~> 5.1) in groups "default" * rake (newest 12.3.1, installed 12.3.0) in groups "default" * rb-fsevent (newest 0.10.3, installed 0.9.8) in groups "test, development" * rb-inotify (newest 0.9.10, installed 0.9.8, requested ~> 0.9) in groups "test, development" * redis (newest 4.0.1, installed 3.3.5) in groups "default" * redis-namespace (newest 1.6.0, installed 1.5.3) in groups "default" * request_store (newest 1.4.1, installed 1.3.2) * rinku (newest 2.0.4, installed 2.0.2) in groups "default" * rotp (newest 3.3.1, installed 3.3.0) in groups "default" * rspec (newest 3.7.0, installed 3.6.0) in groups "test, development" * rspec-core (newest 3.7.1, installed 3.6.0) * rspec-expectations (newest 3.7.0, installed 3.6.0) * rspec-mocks (newest 3.7.0, installed 3.6.0) * rspec-rails (newest 3.7.2, installed 3.6.1) in groups "test, development" * rspec-support (newest 3.7.1, installed 3.6.0) * rubocop (newest 0.54.0, installed 0.53.0) in groups "test, development" * ruby-prof (newest 0.17.0, installed 0.16.2) in groups "development" * sass (newest 3.5.6, installed 3.4.24) * sassc (newest 1.11.4, installed 1.11.2) in groups "default" * seed-fu (newest 2.3.9, installed 2.3.7) in groups "default" * shoulda-matchers (newest 3.1.2, installed 2.8.0) * sidekiq (newest 5.1.3, installed 5.0.5) in groups "default" * slop (newest 4.6.2, installed 3.6.0) * sprockets-rails (newest 3.2.1, installed 3.2.0) in groups "default" * stackprof (newest 0.2.11, installed 0.2.10) in groups "default" * thor (newest 0.20.0, installed 0.19.4) in groups "default" * tilt (newest 2.0.8, installed 2.0.7) in groups "default" * tzinfo (newest 1.2.5, installed 1.2.3) * uglifier (newest 4.1.9, installed 3.2.0) in groups "assets" * unf_ext (newest 0.0.7.5, installed 0.0.7.4) * uniform_notifier (newest 1.11.0, installed 1.10.0) where do I start? • what is most important? • which are the oldest? • what is unmaintained?
  12. $ bin/bundle_report outdated | head -n 5 rack-openid 1.3.1: released

    about 7 years ago (latest version, 1.4.2, released about 4 years ago) method_source 0.8.2: released over 4 years ago (latest version, 0.9.0, released 7 months ago) fabrication 2.9.8: released about 4 years ago (latest version, 2.20.1, released 3 months ago) slop 3.6.0: released over 3 years ago (latest version, 4.6.2, released about 1 month ago) active_model_serializers 0.8.3: released over 3 years ago (latest version, 0.10.7, released 5 months ago)
  13. rack-openid 1.3.1: released about 7 years ago (latest version, 1.4.2,

    released about 4 years ago) name installed version release date newest version release date
  14. $ bin/bundle_report compatibility --rails-version 5.2.0 => Incompatible with Rails 5.2.0

    (with new versions that are compatible): These gems will need to be upgraded before upgrading to Rails 5.2.0. lograge 0.7.1 - upgrade to 0.10.0 => Incompatible with Rails 5.2.0 (with no new compatible versions): These gems will need to be removed or replaced before upgrading to Rails 5.2.0. jquery-rails 4.3.1 - new version, 4.3.1, is not compatible with Rails 5.2.0 2 gems incompatible with Rails 5.2.0
  15. $ bin/bundle_report compatibility --rails-version 5.2.0 => Incompatible with Rails 5.2.0

    (with new versions that are compatible): These gems will need to be upgraded before upgrading to Rails 5.2.0. lograge 0.7.1 - upgrade to 0.10.0 => Incompatible with Rails 5.2.0 (with no new compatible versions): These gems will need to be removed or replaced before upgrading to Rails 5.2.0. jquery-rails 4.3.1 - new version, 4.3.1, is not compatible with Rails 5.2.0 2 gems incompatible with Rails 5.2.0
  16. $ bin/bundle_report compatibility --rails-version 5.2.0 => Incompatible with Rails 5.2.0

    (with new versions that are compatible): These gems will need to be upgraded before upgrading to Rails 5.2.0. lograge 0.7.1 - upgrade to 0.10.0 => Incompatible with Rails 5.2.0 (with no new compatible versions): These gems will need to be removed or replaced before upgrading to Rails 5.2.0. jquery-rails 4.3.1 - new version, 4.3.1, is not compatible with Rails 5.2.0 2 gems incompatible with Rails 5.2.0
  17. $ bin/bundle_report compatibility --rails-version 5.2.0 => Incompatible with Rails 5.2.0

    (with new versions that are compatible): These gems will need to be upgraded before upgrading to Rails 5.2.0. lograge 0.7.1 - upgrade to 0.10.0 => Incompatible with Rails 5.2.0 (with no new compatible versions): These gems will need to be removed or replaced before upgrading to Rails 5.2.0. jquery-rails 4.3.1 - new version, 4.3.1, is not compatible with Rails 5.2.0 2 gems incompatible with Rails 5.2.0
  18. User.find(current_user) # DEPRECATION WARNING: You are passing an instance #

    of ActiveRecord::Base to `find`. Please pass the # id of the object by calling `.id`. (called from <main> at (
  19. { "./spec/controllers/post_controller_spec.rb": [ "DEPRECATION WARNING: env is deprecated and will

    be remov ], "./spec/controllers/session_controller_spec.rb": [ "DEPRECATION WARNING: `xhr` and `xml_http_request` are de "DEPRECATION WARNING: env is deprecated and will be remov ], "./spec/controllers/accounts_controller_spec.rb": [ "DEPRECATION WARNING: Using positional arguments in funct ] }
  20. { "./spec/controllers/post_controller_spec.rb": [ "DEPRECATION WARNING: env is deprecated and will

    be remov ], "./spec/controllers/session_controller_spec.rb": [ "DEPRECATION WARNING: `xhr` and `xml_http_request` are de "DEPRECATION WARNING: env is deprecated and will be remov ], "./spec/controllers/accounts_controller_spec.rb": [ "DEPRECATION WARNING: Using positional arguments in funct ] }
  21. { "./spec/controllers/post_controller_spec.rb": [ "DEPRECATION WARNING: env is deprecated and will

    be remov ], "./spec/controllers/session_controller_spec.rb": [ "DEPRECATION WARNING: `xhr` and `xml_http_request` are de "DEPRECATION WARNING: env is deprecated and will be remov ], "./spec/controllers/accounts_controller_spec.rb": [ "DEPRECATION WARNING: Using positional arguments in funct ] }
  22. $ bin/deprecations info Ten most common deprecation warnings: Occurrences: 608

    DEPRECATION WARNING: Using positional arguments in functional tests has been deprecated, in favor of keyword arguments, and will be removed in Rails 5.1. Deprecated style: get :show, { id: 1 }, nil, { notice: "This is a flash message" } New keyword style: get :show, params: { id: 1 }, flash: { notice: "This is a flash message" }, session: nil # Can safely be omitted. (called from block (3 levels) in <main> at spec/foo.rb:67) ---------- Occurrences: 553 DEPRECATION WARNING: Passing an argument to force an association to reload is now deprecated and will be removed in Rails 5.1. Please call `reload_active_al_subscription` instead. (called from reload_subscriptions at app/models/foo.rb:270) # ...
  23. # top of Gemfile def next? File.basename(__FILE__) == "Gemfile.next" end

    # later if next? gem "rails", "5.2.0" else gem "rails", "5.1.6" end
  24. # top of Gemfile def next? File.basename(__FILE__) == "Gemfile.next" end

    # later if next? gem "rails", "5.2.0" else gem "rails", "5.1.6" end
  25. # top of Gemfile def next? File.basename(__FILE__) == "Gemfile.next" end

    # later if next? gem "rails", "5.2.0" else gem "rails", "5.1.6" end
  26. $ bundle install # install gems $ rails s #

    run rails $ rspec # run tests
  27. $ bin/next bundle install # install gems $ bin/next rails

    s # run rails $ bin/next rspec # run tests
  28. # Try it out $ gem install ten_years_rails_conf_2018 # Or,

    read the code $ open https://github.com/clio/ten_years_rails_conf_2018
  29. $ Tiny Co. % Big Inc. 1. Gems Few Many

    2. Code changes Few Many 3. Test Few failures Won’t even run 4. Deploy Easy Terrifying
  30. $ Tiny Co. % Big Inc. 1. Gems Few Many

    Few 2. Code changes Few Many 3. Test Few failures Won’t even run 4. Deploy Easy Terrifying
  31. $ Tiny Co. % Big Inc. 1. Gems Few Many

    Few 2. Code changes Few Many Few 3. Test Few failures Won’t even run 4. Deploy Easy Terrifying
  32. $ Tiny Co. % Big Inc. 1. Gems Few Many

    Few 2. Code changes Few Many Few 3. Test Few failures Won’t even run Few failures 4. Deploy Easy Terrifying
  33. $ Tiny Co. % Big Inc. 1. Gems Few Many

    Few 2. Code changes Few Many Few 3. Test Few failures Won’t even run Few failures 4. Deploy Easy Less terrifying*