Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to Eat a Whale

How to Eat a Whale

You know you need to make changes. Upgrade your software, pull a Humpy Dumpty on the test suite, tame your production emergencies. And yet you never quite get there.

Let's talk through the strategies that are most effective, and how I've succeeded - and often failed - to get to the other side.

Joseph Mastey

July 12, 2019
Tweet

More Decks by Joseph Mastey

Other Decks in Programming

Transcript

  1. Have you heard of tiny Melinda Mae, Who ate a

    monstrous whale? She thought she could, She said she would, So she started in right at the tail. - Shel Silverstein
  2. ▸ Hard to Maintain ▸ New Features ▸ Better Performance

    ▸ Security ▸ Ergonomics ▸ Hiring
  3. ▸ 1.2 ➡ 4.2 ▸ 3.0 ➡ 5.0 ▸ 4.2

    ➡ 5.0 ▸ 4.2 ➡ 5.0 success success failure ongoing!
  4. source: git log -L 5,6:Gemfile Date Rails Version Jun ‘19

    4.2.11 Aug ‘17 4.2.7.1 Dec ‘16 4.2.7 Mar ‘16 4.1.13 Mar ‘16 4.2.5.2 Feb ‘16 4.2.5.1 Aug ‘15 4.1.13 Jan ‘15 4.1.9 Dec ‘14 4.0.0 … … May ‘13 3.2.8
  5. class Money::Arithmetic def ==(other) # don’t allow comparison w/ non-Money

    objects unless other.is_a? Money || other.zero? raise ArgumentError end # ... do comparison end end
  6. class Money::Arithmetic def ==(other) # warn about problems if other.is_a?(Numeric)

    && other.nonzero? trigger_warning_and_rollbar end super # run actual comparison end end
  7. ‣ rails 5 ‣ factory_bot ‣ belongs_to ‣ protected_attributes ‣

    strong params ‣ activeadmin ‣ devise ‣ upgrade ruby ‣ rails 4.2.11 ‣ sass ‣ coffee ‣ money ‣ etc… ‣ quiet_assets*
  8. ‣ factory bot ‣ add shim ‣ use shim for

    existing cases ‣ upgrade factory girl to most recent version ‣ switch to factory bot and remove shim lots of changes, low risk tiny change, highest risk
  9. # warning: BigDecimal.new is deprecated; # use BigDecimal() method instead.

    (BigDecimal.new('-50.00')..BigDecimal.new('50.00')) => 'cold',
  10. # in rails 4, this is optional # in rails

    5, it’s required belongs_to :packing_facility # this works in both! belongs_to :packing_facility, required: false
  11. NoMethodError: undefined method 'sellout_limit' for nil:NilClass # ./app/models/meal.rb:531:in 'sellout_limit_for' #

    ./app/models/menu.rb:254:in 'meal_sold_out?' # ./app/models/meal_selection.rb:208:in 'validate_meal_selection'
  12. ArgumentError: Couldn’t find 3rd meal for plan 'Standard' in menu

    ’15-jul-2019' (2 meals for plan) # ./spec/factories/weekly_baskets.rb:131:in `validate_selection!' # ./spec/factories/weekly_baskets.rb:61:in `block (5 levels)’ # ./spec/factories/weekly_baskets.rb:58:in `times' # ./spec/factories/weekly_baskets.rb:58:in `block (4 levels)’
  13. # in rails 4, this is optional # in rails

    5, it’s required belongs_to :packing_facility
  14. WeeklyBasket.reflect_on_all_associations.each do |association| next if association.macro != :belongs_to foreign_key_field =

    klass.reflections[association.name.to_s].foreign_key column = klass.columns.find { |c| c.name == foreign_key_field.to_s } required = association.options.fetch(:required, true) && !association.options.fetch(:optional, false) if required && column.null exceptions << sprintf(“%-50s required, but column is nullable", "#{klass}##{association.name}") elsif !required && !column.null exceptions << sprintf("%-50s not required, but column is not nullable", "#{klass}##{association.name}") end end
  15. WeeklyBasket.reflect_on_all_associations.each do |association| end next if association.macro != :belongs_to foreign_key_field

    = klass.reflections[association.name.to_s].foreign_key column = klass.columns.find { |c| c.name == foreign_key_field.to_s } required = association.options.fetch(:required, true) && !association.options.fetch(:optional, false) if required && column.null exceptions << sprintf(“%-50s required, but column is nullable", "#{klass}##{association.name}") elsif !required && !column.null exceptions << sprintf("%-50s not required, but column is not nullable", "#{klass}##{association.name}") end
  16. WeeklyBasket#address will be required, but column is nullable WeeklyBasket#meal_plan will

    be required, but column is nullable WeeklyBasket#shipping_box will be required, but column is nullable WeeklyBasket#shipping_region will be required, but column is nullable
  17. namespace :rails_5 do task check_belongs_to_associations: :environment do silence_warnings do print

    "Eager Loading..." Rails.application.eager_load! puts “done.” # ... do comparison end end end