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

Ellington Intro

Ellington Intro

An introduction to Ruby's Ellington framework.

Nathan Hopkins

February 20, 2013
Tweet

More Decks by Nathan Hopkins

Other Decks in Technology

Transcript

  1. • Establish constraints to ensure that complex projects are easy

    to manage, develop, and maintain. • Provide a nomenclature simple enough to be shared by engineering and the business team. GOALS
  2. • Based on New York City’s subway system. • Establishes

    consistent physical metaphors. • Allows more people to participate. • Manages complexity with simplicity. NOMENCLATURE
  3. • Passenger • Station • Line • Route • Ticket

    • Conductor LEXICON ALMOST SELF EXPLANATORY
  4. PASSENGER • The object that acts as the traveler •

    Has a state property • This state is changed exactly once at each station • Stateful
  5. STATION • Where passengers exit • Where business logic lives

    • Three possible outcomes • PASS • FAIL • ERROR
  6. LINE • Moves passengers from point A to point B

    • A list of Stations • Executed in linear order • Three possible outcomes • PASS • FAIL • ERROR
  7. LINE EXAMPLES • Make API call • Generate invoice •

    Transact payment • Schedule shipment
  8. ROUTE • A collection of Lines • Connects lines in

    non-linear order • Three possible outcomes • PASS • FAIL • ERROR
  9. TICKET • Optional • Issued to a passenger • Qualifies

    the passenger to ride... e.g. security
  10. CONDUCTOR • Manages a single route • Responsible for putting

    passengers on a route • Verifies passengers
  11. • Target - a list of states (i.e. to specify

    a Goal) • Connection - a configuration that ties 2 lines together • Transition - the process of changing a passenger’s state OTHER TERMS
  12. GETTING STARTED • Model business requirements into a simple flow

    chart • Forces analysis and encourages better design • Allows non-developers to participate
  13. • Send a status update to Facebook & Twitter then

    bill the user • Always try to post to both networks • Only post to a network when certain conditions permit • Only bill if we successfully post to both networks SOCIAL BLAST
  14. Social Blast Facebook Verify Token Bill Pass Can Post Should

    Post Verify Credit Card Bill Credit Card Send Notification Post Twitter Verify Token Can Post Should Post Post Facbook Goal Met? Fail Pass Updated both networks? Finish Fail Start
  15. class VerifyFacebookToken < Ellington::Station def engage(user, options) begin # TODO:

    Verify the OAuth token for the user's Facebook account. # Add some fakery so it feels like its working. raise if rand(100) == 0 ok = rand(100) > 5 if ok pass_passenger user else fail_passenger user end rescue error_passenger user end end end
  16. class VerifyFacebookToken < Ellington::Station def engage(user, options) begin # TODO:

    Verify the OAuth token for the user's Facebook account. # Add some fakery so it feels like its working. raise if rand(100) == 0 ok = rand(100) > 5 if ok pass_passenger user else fail_passenger user end rescue error_passenger user end end end
  17. class VerifyFacebookToken < Ellington::Station def engage(user, options) begin # TODO:

    Verify the OAuth token for the user's Facebook account. # Add some fakery so it feels like its working. raise if rand(100) == 0 ok = rand(100) > 5 if ok pass_passenger user else fail_passenger user end rescue error_passenger user end end end
  18. class VerifyFacebookToken < Ellington::Station def engage(user, options) begin # TODO:

    Verify the OAuth token for the user's Facebook account. # Add some fakery so it feels like its working. raise if rand(100) == 0 ok = rand(100) > 5 if ok pass_passenger user else fail_passenger user end rescue error_passenger user end end end
  19. class Facebook < Ellington::Line stations << VerifyFacebookToken.new stations << CanPost.new

    stations << ShouldPost.new stations << Post.new goal stations.last.passed end
  20. class Facebook < Ellington::Line stations << VerifyFacebookToken.new stations << CanPost.new

    stations << ShouldPost.new stations << Post.new goal stations.last.passed end
  21. class Facebook < Ellington::Line stations << VerifyFacebookToken.new stations << CanPost.new

    stations << ShouldPost.new stations << Post.new goal stations.last.passed end
  22. class Facebook < Ellington::Line stations << VerifyFacebookToken.new stations << CanPost.new

    stations << ShouldPost.new stations << Post.new goal stations.last.passed end
  23. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  24. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  25. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  26. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  27. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  28. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  29. class Blast < Ellington::Route facebook = Facebook.new twitter = Twitter.new

    billing = Billing.new lines << facebook # entry line since its the first added lines << twitter lines << billing connect_to twitter, :if_any => [facebook.passed, facebook.failed, facebook.errored] connect_to billing, :if_all => [facebook.passed, twitter.passed] goal billing.passed # extra attributes we want to log # these exist on the user log_options :passenger => [:id, :current_message] end
  30. INTELLIGENT LOGGING [STATION COMPLETED] [PASS] [VerifyFacebookToken::Facebook::Blast] [id:1b56efc7-52bc-4ecd-a9c [STATION COMPLETED] [PASS]

    [CanPost::Facebook::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5a [STATION COMPLETED] [PASS] [ShouldPost::Facebook::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1 [STATION COMPLETED] [PASS] [Post::Facebook::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [LINE COMPLETED] [PASS] [Facebook::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [current [STATION COMPLETED] [PASS] [VerifyTwitterToken::Twitter::Blast] [id:1b56efc7-52bc-4ecd-a9cc- [STATION COMPLETED] [PASS] [CanTweet::Twitter::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5a [STATION COMPLETED] [PASS] [ShouldTweet::Twitter::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1 [STATION COMPLETED] [PASS] [Tweet::Twitter::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [LINE COMPLETED] [PASS] [Twitter::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [current_ [STATION COMPLETED] [PASS] [VerifyCreditCard::Billing::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea [STATION COMPLETED] [PASS] [BillCreditCard::Billing::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86 [STATION COMPLETED] [PASS] [SendBillingNotification::Billing::Blast] [id:1b56efc7-52bc-4ecd- [LINE COMPLETED] [PASS] [Billing::Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [current_ [ROUTE COMPLETED] [PASS] [Blast] [id:1b56efc7-52bc-4ecd-a9cc-ea86ab1d5ab6] [current_message: [STATION COMPLETED] [PASS] [VerifyFacebookToken::Facebook::Blast] [id:28997780-a55e-48ea-ae7 [STATION COMPLETED] [PASS] [CanPost::Facebook::Blast] [id:28997780-a55e-48ea-ae74-e8549da78e [STATION COMPLETED] [PASS] [ShouldPost::Facebook::Blast] [id:28997780-a55e-48ea-ae74-e8549da [STATION COMPLETED] [PASS] [Post::Facebook::Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [LINE COMPLETED] [PASS] [Facebook::Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [current [STATION COMPLETED] [PASS] [VerifyTwitterToken::Twitter::Blast] [id:28997780-a55e-48ea-ae74- [STATION COMPLETED] [PASS] [CanTweet::Twitter::Blast] [id:28997780-a55e-48ea-ae74-e8549da78e [STATION COMPLETED] [PASS] [ShouldTweet::Twitter::Blast] [id:28997780-a55e-48ea-ae74-e8549da [STATION COMPLETED] [PASS] [Tweet::Twitter::Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [LINE COMPLETED] [PASS] [Twitter::Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [current_ [STATION COMPLETED] [PASS] [VerifyCreditCard::Billing::Blast] [id:28997780-a55e-48ea-ae74-e8 [STATION COMPLETED] [FAIL] [BillCreditCard::Billing::Blast] [id:28997780-a55e-48ea-ae74-e854 [LINE COMPLETED] [FAIL] [Billing::Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [current_ [ROUTE COMPLETED] [FAIL] [Blast] [id:28997780-a55e-48ea-ae74-e8549da78ebb] [current_message: [STATION COMPLETED] [PASS] [VerifyFacebookToken::Facebook::Blast] [id:862c65f8-9958-49aa-991 [STATION COMPLETED] [PASS] [CanPost::Facebook::Blast] [id:862c65f8-9958-49aa-9918-0c6a0d3237
  31. [3] pry(main)> Blast.states => {"PRE Blast"=> ["PASS VerifyFacebookToken::Facebook", "FAIL VerifyFacebookToken::Facebook",

    "ERROR VerifyFacebookToken::Facebook"], "PASS VerifyFacebookToken::Facebook"=> ["PASS CanPost::Facebook", "FAIL CanPost::Facebook", "ERROR CanPost::Facebook", "PASS VerifyTwitterToken::Twitter", "FAIL VerifyTwitterToken::Twitter", "ERROR VerifyTwitterToken::Twitter"], "FAIL VerifyFacebookToken::Facebook"=> ["PASS VerifyTwitterToken::Twitter", "FAIL VerifyTwitterToken::Twitter", "ERROR VerifyTwitterToken::Twitter"], "ERROR VerifyFacebookToken::Facebook"=> ["PASS VerifyFacebookToken::Facebook", "FAIL VerifyFacebookToken::Facebook", "ERROR VerifyFacebookToken::Facebook", "PASS VerifyTwitterToken::Twitter", "FAIL VerifyTwitterToken::Twitter", "ERROR VerifyTwitterToken::Twitter"], STATES & TRANSITIONS
  32. TAKE AWAYS • Encourages better design • Very light •

    Understandable • Modular • Composable • Testable
  33. BENEFITS & USES • Demands up-front BPM • Structured query-able

    logs • Facilitates monitoring & analytics • Passenger visualizations support self-help administration