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

Testing Isn't Enough: Fighting Bugs with Hacks

Paul Gross
November 17, 2014

Testing Isn't Enough: Fighting Bugs with Hacks

This talk was given at RubyConf 2014.

Paul Gross

November 17, 2014
Tweet

More Decks by Paul Gross

Other Decks in Programming

Transcript

  1. Mars Climate Orbiter September 23, 1999: Bug in calculation units

    caused the spacecraft to burn up in Mars atmosphere
  2. World of Warcraft Plague September 13, 2005: Bug in a

    spell caused a pandemic through the virtual world
  3. If debugging is the process of removing bugs, then programming

    must be the process of putting them in. — Edsger W. Dijkstra Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence. — Edsger W. Dijkstra
  4. Mitigation • Fail fast when we know there is a

    problem • Structure our systems to reduce the severity of bugs
  5. Strategy • Figure out the invariants of a system •

    Add runtime checks for these invariants
  6. Strategy • Figure out the invariants of a system •

    Add runtime checks for these invariants • Raise and alert so the issue can be investigated and fixed
  7. >> Customer.where(:token => 'Paul') RuntimeError: #finds must be scoped on

    Customer >> merchant = Merchant.find(1) >> merchant.customers.where(:token => 'Paul') [#<Customer id: 1 ...
  8. class ApplicationController < ActionController::Base around_filter :ensure_merchant_consistency def ensure_merchant_consistency(&block) @merchant =

    Merchant.find_by!(:public_id => params["merchant_id"]) MerchantConsistencyCheck.with_merchant(@merchant, &block) end end
  9. class ApplicationController < ActionController::Base around_filter :ensure_merchant_consistency def ensure_merchant_consistency(&block) @merchant =

    Merchant.find_by!(:public_id => params["merchant_id"]) MerchantConsistencyCheck.with_merchant(@merchant, &block) end end ... Customer.find_by_sql(["SELECT * FROM customers WHERE token = ?", "Paul"]) ScopedFindHook::ScopeError: Customer cannot return objects scoped by the incorrect merchant. Got 6, expected 1.
  10. Strategy • Focus on the validity of the data •

    Code can be fixed more easily than data
  11. Check data consistency if billing_period_start_date > billing_period_end_date raise "Subscription internal

    state is inconsistent -- " + "billing_period_start_date vs billing_period_end_date: #{inspect}" end
  12. Check data consistency if billing_period_start_date > billing_period_end_date raise "Subscription internal

    state is inconsistent -- " + "billing_period_start_date vs billing_period_end_date: #{inspect}" end if _correct_next_billing_date != next_billing_date raise "Subscription internal state is inconsistent -- " + "next_billing_date incorrect: #{inspect}" end
  13. Strategy • Write checks outside of the normal flow •

    Keep checking code simpler than real code
  14. require 'spec_helper' describe 'Sanity Specs' do it "has a unique

    index on every public_id column" do indexes = ActiveRecord::Base.connection.select_values(<<-SQL) SELECT relname FROM pg_class WHERE relkind = 'i'" SQL ActiveRecord::Base.connection.tables.each do |table| indexes.grep(/index_#{table}_on.*public_id/).size.should eql(1), "#{table} does not have an index on public_id" end end end
  15. Summary • Check for invariants • Focus on data validity

    • Write checks outside of the normal flow
  16. Summary • Check for invariants • Focus on data validity

    • Write checks outside of the normal flow • Find your own examples
  17. Photo Credits Mars Climate Orbiter: Courtesy NASA/JPL-Caltech World of Warcraft:

    ©2004 Blizzard Entertainment, Inc. Bugs: flickr.com/photos/editor/11341534765 (CC BY 2.0) NYSE: flickr.com/photos/ilamont/5538510845 (CC BY 2.0) Testing: flickr.com/photos/sidelong/246816211 (CC BY 2.0) Kids don't float: flickr.com/photos/iluvcocacola/535258842 (CC BY-NC-ND 2.0) Pillars: flickr.com/photos/tom-carden/80262 (CC BY-NC-SA 2.0)
  18. Photo Credits CDs: flickr.com/photos/swanksalot/2704017177 (CC BY-SA 2.0) Fence: flickr.com/photos/clonedmilkmen/2971765601 (CC

    BY- SA 2.0) Hacking: flickr.com/photos/adulau/9464930917 (CC BY-SA 2.0) Safety First: flickr.com/photos/krossbow/434064539 (CC BY 2.0)