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

Make an Event of It! (ConFoo 2014)

Make an Event of It! (ConFoo 2014)

The upsurge in asynchronous programming has brought event-driven patterns to the forefront. But even without a rewrite in Node.js, the concept of eventing can improve your application.

This talk demonstrates how events benefit the layers of your application. We'll see how events aid in the fight against fat controllers. We'll use eventing to simplify tests and manage dependencies. We'll even see events reshape our data for maximum flexibility.

Jason R Clark

February 27, 2014
Tweet

More Decks by Jason R Clark

Other Decks in Technology

Transcript

  1. Jason Clark @jasonrclark Ruby Agent Engineer Make an Event of

    It! Evented Patterns in Ruby Wednesday, February 26, 14
  2. Events Aren't (Necessarily) 4 • Asynchronous • IO related •

    Distributed • Complicated Wednesday, February 26, 14
  3. Where Are We Going? • The Pattern • Internal Coupling

    • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 5 Wednesday, February 26, 14
  4. 11 class Subscription < ActiveRecord::Base before_create :record_signup private def record_signup

    self.signed_up_on = Date.today end end Wednesday, February 26, 14
  5. 11 class Subscription < ActiveRecord::Base before_create :record_signup private def record_signup

    self.signed_up_on = Date.today end end Wednesday, February 26, 14
  6. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 12 Wednesday, February 26, 14
  7. {server config} 14 app start connect() New Relic Server ?

    newrelic_rpm Wednesday, February 26, 14
  8. 17 def test_finish_setup_naming_rules config = { 'rules' => [...] }

    @agent.finish_setup(config) assert_equal 2, @agent.transaction_rules.size end newrelic_rpm Wednesday, February 26, 14
  9. 18 def test_finish_setup_naming_rules @agent.cross_app_tracing.stub(:set_key) @agent.js_instrumentor.stub(:log_config) config = { 'rules' =>

    [...] } @agent.finish_setup(config) assert_equal 2, @agent.transaction_rules.size end newrelic_rpm Wednesday, February 26, 14
  10. 21 class Beacon def initialize # Your code is bad

    and you should feel bad Net::HTTP.get("http://somewhere.com") end end newrelic_rpm Wednesday, February 26, 14
  11. 22 def test_finish_setup_naming_rules @agent.cross_app_tracing.stub(:set_key) @agent.js_instrumentor.stub(:log_config) Beacon.stub(:new).return(stub("fake beacon")) config = {

    'rules' => [...] } @agent.finish_setup(config) assert_equal 2, @agent.transaction_rules.size end newrelic_rpm Wednesday, February 26, 14
  12. 26 def test_finish_setup_notifies called = false @events.subscribe(:configured) do called =

    true end @agent.finish_setup({}) assert called end newrelic_rpm Wednesday, February 26, 14
  13. 27 def test_add_naming_rules config = { 'rules' => [...] }

    @agent.add_naming_rules(config) assert_equal 2, @agent.transaction_rules.size end newrelic_rpm Wednesday, February 26, 14
  14. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 33 Wednesday, February 26, 14
  15. 37 module NewRelic::Rack class AgentHooks def call(env) notify(:before_call, env) result

    = @app.call(env) notify(:after_call, env, result) result end end end newrelic_rpm Wednesday, February 26, 14
  16. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 42 Wednesday, February 26, 14
  17. 46 class SimpleEvents::Notifier def initialize @events = {} ... end

    end simple_events Wednesday, February 26, 14
  18. 47 class SimpleEvents::Notifier ... def subscribe(event, &handler) @events[event] ||= []

    @events[event] << handler check_for_runaway_subscriptions(event) end ... end simple_events Wednesday, February 26, 14
  19. 48 class SimpleEvents::Notifier ... def notify(event, *args) return unless @events.has_key?(event)

    @events[event].each do |handler| begin handler.call(*args) rescue => err logger.debug("Fail #{@event}", err) end end end end simple_events Wednesday, February 26, 14
  20. 49 class SimpleEvents::Notifier ... def notify(event, *args) return unless @events.has_key?(event)

    @events[event].each do |handler| begin handler.call(*args) rescue => err logger.debug("Fail #{@event}", err) end end end end simple_events Wednesday, February 26, 14
  21. 50 class SimpleEvents::Notifier ... def notify(event, *args) return unless @events.has_key?(event)

    @events[event].each do |handler| begin handler.call(*args) rescue => err logger.debug("Fail #{@event}", err) end end end end simple_events Wednesday, February 26, 14
  22. 51 class SimpleEvents::Notifier ... def notify(event, *args) return unless @events.has_key?(event)

    @events[event].each do |handler| begin handler.call(*args) rescue => err logger.debug("Fail #{@event}", err) end end end end simple_events Wednesday, February 26, 14
  23. 52 class SimpleEvents::Notifier ... def notify(event, *args) return unless @events.has_key?(event)

    @events[event].each do |handler| begin handler.call(*args) rescue => err logger.debug("Fail #{@event}", err) end end end end simple_events Wednesday, February 26, 14
  24. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 53 Wednesday, February 26, 14
  25. 59 e = AS::Notifications::Event.new(*args) e.name # => "render_template..." e.duration #

    => 10 (in milliseconds) e.payload # => { :identifier => ... } activesupport Wednesday, February 26, 14
  26. 61 AS::Notifications.instrument("evt", :data => 1) do #... your timed code

    here end activesupport Wednesday, February 26, 14
  27. • Regexp on Notifications.subscribe • Event#parent_of? • Temporary subscription •

    Unsubscribe • LogSubscriber 62 activesupport Wednesday, February 26, 14
  28. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Events • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 63 Wednesday, February 26, 14
  29. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Events • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 69 Wednesday, February 26, 14
  30. 74 class UserSignup < Mutations::Command def execute user = User.create!(inputs)

    NewsletterSubscriptions.create(user.id) UserMailer.async(:deliver_welcome, user.id) user end end Wednesday, February 26, 14
  31. Where Have We Been? • The Pattern • Internal Coupling

    • External Coupling • Adding Events • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data 77 Wednesday, February 26, 14
  32. 79 Opened Account $100 Check 0001 -$15 Deposit $20 Check

    0002 -$21 Total $84 Bank Transactions Wednesday, February 26, 14
  33. 80 customer_id date plan 1 1/1/2013 basic 1 1/2/2013 premium

    1 2/1/2013 basic 1 2/2/2013 premium Customer Pricing Wednesday, February 26, 14
  34. 80 customer_id date plan 1 1/1/2013 basic 1 1/2/2013 premium

    1 2/1/2013 basic 1 2/2/2013 premium Customer Pricing Wednesday, February 26, 14
  35. Other Examples 89 • Database replication • Log files •

    PubSub • Immutable data structures Wednesday, February 26, 14
  36. Jason Clark @jasonrclark Ruby Agent Engineer • The Pattern •

    Internal Coupling • External Coupling • Adding Eventing • ActiveSupport::Notifications • Notifiers • Subscribers • Events as Data ? Wednesday, February 26, 14