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

Here Be Dragons

Katrina Owen
September 15, 2013

Here Be Dragons

It's not your fault. Code rots. We don't hold entropy against you, but we expect you to give a damn.

This story is about code that brings new meaning to the word 'legacy'. The accidental discovery of this body of code provoked a moral crisis. I wanted to pretend I hadn’t seen it, yet I couldn't justify tiptoeing quietly away.

This talk examines the dilemmas we face when balancing our choices today with their cost tomorrow.

It's not your fault. Even so, it is your responsibility.

Katrina Owen

September 15, 2013
Tweet

More Decks by Katrina Owen

Other Decks in Programming

Transcript

  1. here be
    dragons
    katrina owen
    @kytrinyx
    jumpstart lab

    View full-size slide

  2. beezelbuB
    guile 93
    havoc 87
    speed 81
    health 66
    villain
    Armor
    invisible
    cloak

    View full-size slide

  3. princess 0 dragon
    000 000

    View full-size slide

  4. princess 0 dragon
    001
    take that you
    filthy scum...
    000

    View full-size slide

  5. guile 12
    havoc 68
    speed 27
    health 39
    Bubba
    villain
    weapon
    sledge
    hammer

    View full-size slide

  6. guile 2
    havoc 0
    speed 23
    health 98
    ALICE
    Villager
    magic item
    binoculars

    View full-size slide

  7. Weight 9
    length 21
    speed 0
    health 99
    Nelson
    Baby Villager
    Magic Item
    Rattle

    View full-size slide

  8. It is dark...

    View full-size slide

  9. I tried to share
    by email but
    nothing happened.

    View full-size slide

  10. HTTP/1.1 500 Internal Server Error

    View full-size slide

  11. HTTP/1.1 500 Internal Server Error

    View full-size slide

  12. request.form_input"=>#<StringIO:0x007fcbb690f540>, "rack.request.form_hash"=>{"emails"=>&quo
    [email protected]", "message"=>"", "name"=>"Katrina"},
    uot;rack.request.form_vars"=>"[email protected]&message=&name=Katrina",
    uot;action_dispatch.request.path_parameters"=>{:action=>"share_by_mail_or_sms", :controller=>"greetings
    94524"}, "action_controller.instance"=>#<GreetingsController:0x007fcbb7b2ca98 ...>,
    uot;action_dispatch.request.request_parameters"=>{"emails"=>"[email protected]",
    uot;message"=>"", "name"=>"Katrina"}, "rack.request.query_string"=>"&quot
    uot;rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request
    quot;emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    uot;action"=>"share_by_mail_or_sms", "controller"=>"greetings", "id"=>"34
    uot;action_dispatch.request.accepts"=>[*/*], "action_dispatch.request.formats"=>[*/*]}, @fullpath="/tidbit
    are_by_email_or_sms", @filtered_parameters={"emails"=>"[email protected]", "message"=&g
    uot;name"=>"Katrina", "action"=>"share_by_mail_or_sms", "controller"=>"gr
    uot;id"=>"3494524"}, @method="POST">, @_env={"CONTENT_LENGTH"=>"57",
    uot;CONTENT_TYPE"=>"application/x-www-form-urlencoded", "GATEWAY_INTERFACE"=>"CGI/1.1",
    uot;PATH_INFO"=>"/tidbits/123/share_by_email_or_sms", "QUERY_STRING"=>"", "REMOTE_ADDR
    7.0.0.1", "REMOTE_HOST"=>"localhost", "REQUEST_METHOD"=>"POST",
    uot;REQUEST_URI"=>"http://gossip.dev/tidbits/123/share_by_email_or_sms", "SCRIPT_NAME"=>"",
    uot;SERVER_NAME"=>"localhost", "SERVER_PORT"=>"3000", "SERVER_PROTOCOL"=>&quot
    uot;SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)", "HTTP_USER_AGENT"=>"curl/7.21.4 (
    rwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5", "HTTP_HOST"=>"gossip.dev", "HTTP_ACCEPT"=
    uot;rack.version"=>[1, 1], "rack.input"=>#<StringIO:0x007fcbb690f540>, "rack.errors"=>#<I
    uot;rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false,
    uot;rack.url_scheme"=>"http", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_PATH"=>&quo
    uot;action_dispatch.parameter_filter"=>[:password], "action_dispatch.secret_token"=>"
    93f4924fec841d60443d392ff861b0da3ed5d024656a3afd79632dc52355a2aac249ccd32eba784fd61af2dbfc38fcb9ba5f1b6300696de3fc5cb14733198c"
    uot;action_dispatch.remote_ip"=>127.0.0.1, "rack.session"=>{"session_id"=>"a7e33d9fc77a10921f
    uot;id"=>"bffb03fdf02a04a13e4c1ef5f2dad949208ae264c248e690"}, "rack.session.options"=>{:path=>&quo
    uot;, :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :id=>"a7e33d9fc77a10921f460103c25e38fa&
    uot;action_dispatch.cookies"=>{}, "action_dispatch.request.unsigned_session_cookie"=>
    quot;session_id"=>"a7e33d9fc77a10921f460103c25e38fa"}, "action_dispatch.request.content_type"=>applic
    lencoded, "rack.request.form_input"=>#<StringIO:0x007fcbb690f540>, "rack.request.form_hash"=>
    quot;emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    uot;rack.request.form_vars"=>"[email protected]&message=&name=Katrina",
    uot;action_dispatch.request.path_parameters"=>{:action=>"share_by_mail_or_sms", :controller=>"greetings
    94524"}, "action_controller.instance"=>#<GreetingsController:0x007fcbb7b2ca98 ...>,
    uot;action_dispatch.request.request_parameters"=>{"emails"=>"[email protected]",
    uot;message"=>"", "name"=>"Katrina"}, "rack.request.query_string"=>"&quot
    uot;rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request
    quot;emails"=>"[email protected]", "message"=>"", "name"=>"Katrina

    View full-size slide

  13. curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME"

    View full-size slide

  14. curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME" \
    > out.html

    View full-size slide

  15. curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME" \
    > out.html
    open out.html

    View full-size slide

  16. NoMethodError

    View full-size slide

  17. class TidbitsController < ApplicationController
    # ~500 lines of code
    end

    View full-size slide

  18. class TidbitsController < ApplicationController
    skip_before_filter :xyz,
    :only => [:share_by_email_or_sms]
    # ~500 lines of code
    end

    View full-size slide

  19. curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME"

    View full-size slide

  20. ENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
    quot;HTTP_HOST"=>"gossip.dev", "HTTP_ACCEPT"=>"*/*", "rack.version"=>[1, 1],
    quot;rack.input"=>#<StringIO:0x007fcbb6838ae0>, "rack.errors"=>#<IO:<STDERR>>,
    quot;rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false,
    quot;rack.url_scheme"=>"http", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_PATH"=>&quo
    quot;action_dispatch.parameter_filter"=>[:password], "action_dispatch.secret_token"=>"
    a93f4924fec841d60443d392ff861b0da3ed5d024656a3afd79632dc52355a2aac249ccd32eba784fd61af2dbfc38fcb9ba5f1b6300696de3fc5cb14733198c"
    quot;action_dispatch.remote_ip"=>127.0.0.1, "rack.session"=>{"session_id"=>"0c69cf043ced70e9ef
    quot;id"=>"058d52bacce4d0ba74276ce4561d46a65730347c78c11a94", "channel_id"=>176}, "rack.session.o
    :path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :id=>"
    c69cf043ced70e9efd08cb1e7786890"}, "action_dispatch.cookies"=>{}, "action_dispatch.request.unsigned_session_co
    "session_id"=>"0c69cf043ced70e9efd08cb1e7786890"}, "action_dispatch.request.content_type"=>applic
    rlencoded, "rack.request.form_input"=>#<StringIO:0x007fcbb6838ae0>, "rack.request.form_hash"=>
    "emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    quot;rack.request.form_vars"=>"[email protected]&message=&name=Katrina",
    quot;action_dispatch.request.path_parameters"=>{:action=>"share_by_mail_or_sms", :controller=>"greetings
    494524"}, "action_controller.instance"=>#<GreetingsController:0x007fcbb7a5bbf0 ...>,
    quot;action_dispatch.request.request_parameters"=>{"emails"=>"[email protected]",
    quot;message"=>"", "name"=>"Katrina"}, "rack.request.query_string"=>"&quot
    quot;rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request
    "emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    quot;action"=>"share_by_mail_or_sms", "controller"=>"greetings", "id"=>"34
    quot;greeting"=>#<Greeting id: 3494524, title: "12 år 12.12.12", body: "Hipp hurra for jiinta vår! \r\nGrat
    ed ...", happens_on: "2012-12-12", created_at: "2012-12-10 08:53:43", updated_at: "2012-12-11 00:00:33&
    76, display_mode_id: 5344, created_by: 9845, updated_by: 1, owner_name: "Leif Jørgen Larsen", age: 12, session_hash: nil, s
    012-12-10 08:53:43", removed_at: nil, price: 0, kudos_count: 3, about: "Hanne Mari Larsen", uploaded_at: nil, claimed_
    omment_count: 0, kind: "birthday", publish_on: nil, view_count: 22, image_uid: "image:apdm.gossip.oa.birthday$20121210
    onfirmation_sent_at: "2012-12-10 08:53:43">, "sms_message"=>"Katrina vil at du skal se på en hilsen he
    is/personalia/greetings/3494524 Sendt fra www.gossip.dev"}, "action_dispatch.request.accepts"=>[*/*],
    quot;action_dispatch.request.formats"=>[*/*]}, @lookup_context=#<ActionView::LookupContext:0x007fcbb7a5aca0 @details_key=n
    details={:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml, :haml], :formats=>
    :html, :text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json], :locale=>[:"no-NB&
    B"]}, @skip_default_locale=false, @frozen_formats=false, @view_paths=[/Users/katrina/code/apps/gossip/app/views, /Users/katrina/
    endor/plugins/papertime_client/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/origo_client/app/views, /Users/katrina/code/
    lugins/model_bars/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/crummy/app/views, /Users/katrina/code/apps/gossip/vendor/
    pdm_stationary_client/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/acts_as_tsearch/app/views, /Users/katrina/code/apps/g
    ctive_merchant/app/views, /Users/katrina/.rvm/gems/ruby-1.9.3-p194@gossip/gems/kaminari-0.13.0/app/views]>,
    _action_name="share_by_mail_or_sms", @_response_body=nil, @crumbtrail=[{:title=>"Forsiden", :url=>"htt
    ww.gossip.dev"}, {:title=>"Folk i dag", :url=>"/vis/personalia/greetings"}], @_config={}, @current_cha
    76, name: "Oppland Arbeiderblad", home_page: "http://www.gossip.dev", created_at: "2010-09-22 08:33:43"

    View full-size slide

  21. ENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
    quot;HTTP_HOST"=>"gossip.dev", "HTTP_ACCEPT"=>"*/*", "rack.version"=>[1, 1],
    quot;rack.input"=>#<StringIO:0x007fcbb6838ae0>, "rack.errors"=>#<IO:<STDERR>>,
    quot;rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false,
    quot;rack.url_scheme"=>"http", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_PATH"=>&quo
    quot;action_dispatch.parameter_filter"=>[:password], "action_dispatch.secret_token"=>"
    a93f4924fec841d60443d392ff861b0da3ed5d024656a3afd79632dc52355a2aac249ccd32eba784fd61af2dbfc38fcb9ba5f1b6300696de3fc5cb14733198c"
    quot;action_dispatch.remote_ip"=>127.0.0.1, "rack.session"=>{"session_id"=>"0c69cf043ced70e9ef
    quot;id"=>"058d52bacce4d0ba74276ce4561d46a65730347c78c11a94", "channel_id"=>176}, "rack.session.o
    :path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :id=>"
    c69cf043ced70e9efd08cb1e7786890"}, "action_dispatch.cookies"=>{}, "action_dispatch.request.unsigned_session_co
    "session_id"=>"0c69cf043ced70e9efd08cb1e7786890"}, "action_dispatch.request.content_type"=>applic
    rlencoded, "rack.request.form_input"=>#<StringIO:0x007fcbb6838ae0>, "rack.request.form_hash"=>
    "emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    quot;rack.request.form_vars"=>"[email protected]&message=&name=Katrina",
    quot;action_dispatch.request.path_parameters"=>{:action=>"share_by_mail_or_sms", :controller=>"greetings
    494524"}, "action_controller.instance"=>#<GreetingsController:0x007fcbb7a5bbf0 ...>,
    quot;action_dispatch.request.request_parameters"=>{"emails"=>"[email protected]",
    quot;message"=>"", "name"=>"Katrina"}, "rack.request.query_string"=>"&quot
    quot;rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request
    "emails"=>"[email protected]", "message"=>"", "name"=>"Katrina
    quot;action"=>"share_by_mail_or_sms", "controller"=>"greetings", "id"=>"34
    quot;greeting"=>#<Greeting id: 3494524, title: "12 år 12.12.12", body: "Hipp hurra for jiinta vår! \r\nGrat
    ed ...", happens_on: "2012-12-12", created_at: "2012-12-10 08:53:43", updated_at: "2012-12-11 00:00:33&
    76, display_mode_id: 5344, created_by: 9845, updated_by: 1, owner_name: "Leif Jørgen Larsen", age: 12, session_hash: nil, s
    012-12-10 08:53:43", removed_at: nil, price: 0, kudos_count: 3, about: "Hanne Mari Larsen", uploaded_at: nil, claimed_
    omment_count: 0, kind: "birthday", publish_on: nil, view_count: 22, image_uid: "image:apdm.gossip.oa.birthday$20121210
    onfirmation_sent_at: "2012-12-10 08:53:43">, "sms_message"=>"Katrina vil at du skal se på en hilsen he
    is/personalia/greetings/3494524 Sendt fra www.gossip.dev"}, "action_dispatch.request.accepts"=>[*/*],
    quot;action_dispatch.request.formats"=>[*/*]}, @lookup_context=#<ActionView::LookupContext:0x007fcbb7a5aca0 @details_key=n
    details={:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml, :haml], :formats=>
    :html, :text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json], :locale=>[:"no-NB&
    B"]}, @skip_default_locale=false, @frozen_formats=false, @view_paths=[/Users/katrina/code/apps/gossip/app/views, /Users/katrina/
    endor/plugins/papertime_client/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/origo_client/app/views, /Users/katrina/code/
    lugins/model_bars/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/crummy/app/views, /Users/katrina/code/apps/gossip/vendor/
    pdm_stationary_client/app/views, /Users/katrina/code/apps/gossip/vendor/plugins/acts_as_tsearch/app/views, /Users/katrina/code/apps/g
    ctive_merchant/app/views, /Users/katrina/.rvm/gems/ruby-1.9.3-p194@gossip/gems/kaminari-0.13.0/app/views]>,
    _action_name="share_by_mail_or_sms", @_response_body=nil, @crumbtrail=[{:title=>"Forsiden", :url=>"htt
    ww.gossip.dev"}, {:title=>"Folk i dag", :url=>"/vis/personalia/greetings"}], @_config={}, @current_cha
    76, name: "Oppland Arbeiderblad", home_page: "http://www.gossip.dev", created_at: "2010-09-22 08:33:43"

    View full-size slide

  22. I18n::MissingInterpolationArgument

    View full-size slide

  23. controller
    share_by_email_or_sms

    View full-size slide

  24. controller
    share_by_email_or_sms

    View full-size slide

  25. module
    share_by_email_or_sms

    View full-size slide

  26. module
    share_by_email_or_sms
    send_to_recipients

    View full-size slide

  27. share_by_email_or_sms
    send_to_recipients
    send_to_email
    module

    View full-size slide

  28. share_by_email_or_sms
    send_to_recipients
    send_to_email
    module

    View full-size slide

  29. mailer
    share_by_email_or_sms
    send_to_recipients
    send_to_email

    View full-size slide

  30. mailer
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip

    View full-size slide

  31. mailer
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip

    View full-size slide

  32. template
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip
    tidbit_tip.text.erb

    View full-size slide

  33. template
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip
    tidbit_tip.text.erb

    View full-size slide

  34. i18n
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip
    tidbit_tip.text.erb

    View full-size slide

  35. i18n
    share_by_email_or_sms
    send_to_recipients
    send_to_email
    tidbit_tip
    tidbit_tip.text.erb
    I18n.translate

    View full-size slide

  36. i18n
    missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)

    View full-size slide

  37. Error Message
    missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)

    View full-size slide

  38. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  39. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  40. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  41. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  42. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  43. missing interpolation argument in
    "%{tidbit_sender} has congratulated
    %{tidbit_about} in %{publication}.
    %{tip_sender} wants you to take a look."
    (
    {
    :tip_sender=>"Katrina",
    :tidbit_about=>"Eve Smith",
    :publication=>"The Village Rag"
    }
    given)
    Error Message

    View full-size slide

  44. error message
    <%= t("emails.tip_mail.introduction") % {
    :tip_sender => @tip_sender,
    :tidbit_about => @tidbit.about,
    :publication => @tidbit.publication
    }
    %>

    View full-size slide

  45. template
    <%= t("emails.tip_mail.introduction") % {
    :tip_sender => @tip_sender,
    :tidbit_about => @tidbit.about,
    :publication => @tidbit.publication
    }
    %>

    View full-size slide

  46. <%= t("emails.tip_mail.introduction") % {
    :tip_sender => @tip_sender,
    :tidbit_about => @tidbit.about,
    :publication => @tidbit.publication
    :tidbit_sender => @tidbit.from
    }
    %>
    template

    View full-size slide

  47. curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME"

    View full-size slide

  48. HTTP/1.1 200 OK
    {
    "success": ["[email protected]"]
    }

    View full-size slide

  49. HTTP/1.1 200 OK
    {
    "success": ["[email protected]"]
    }
    1up

    View full-size slide

  50. 1 new message
    HTTP/1.1 200 OK
    {
    "success": ["[email protected]"]
    }

    View full-size slide

  51. All your bugs are
    belong to us...

    View full-size slide

  52. This could be
    dangerous...

    View full-size slide

  53. class TidbitsController < ApplicationController
    # ~500 lines of code
    end

    View full-size slide

  54. controller
    class TidbitsController < ApplicationController
    # ~500 lines of code
    end

    View full-size slide

  55. class TidbitsController < ApplicationController
    def share_by_email_or_sms
    # ...
    end
    end
    controller

    View full-size slide

  56. controller
    def share_by_email_or_sms
    # ...
    tinyurl = Tinyurl.shorten(tidbit.url)
    # ...
    end

    View full-size slide

  57. module Tinyurl
    # ~75 lines of code
    end
    controller

    View full-size slide

  58. module Tinyurl
    # ~75 lines of code
    end
    module

    View full-size slide

  59. # Base exception class
    module

    View full-size slide

  60. # Base exception class
    class TinyurlException < Exception
    end
    module

    View full-size slide

  61. # Exception class
    module

    View full-size slide

  62. # Exception class
    class InvalidUrlException < TinyurlException
    end
    module

    View full-size slide

  63. # Get a nice one from the API
    module

    View full-size slide

  64. # Get a nice one from the API
    def self.lookup_tiny_url(url)
    # 16 LOC
    end
    module

    View full-size slide

  65. # If we sohuld ask the API...
    module

    View full-size slide

  66. # If we sohuld ask the API...
    def self.should_lookup_tiny_url?
    # 7 LOC
    end
    module

    View full-size slide

  67. def self.lookup_tiny_url(url)
    # ...
    uri = URI.parse(endpoint)
    Net::HTTP.start(uri.host, uri.port) do |api|
    api.get("#{uri.path}?#{uri.query}")
    end
    # ...
    end
    def self.endpoint
    "http://is.gd/create.php"
    end
    module

    View full-size slide

  68. def self.should_lookup_tiny_url?
    return false if cached?
    # ...
    end
    module

    View full-size slide

  69. def self.should_lookup_tiny_url?
    return false if cached?
    case env
    when "production" then return true
    when "staging" then return true
    else return false
    end
    false
    end
    module

    View full-size slide

  70. def self.should_lookup_tiny_url?
    return false if cached?
    case env
    when "production" then return true
    when "staging" then return true
    else return false
    end
    false
    end
    module

    View full-size slide

  71. module
    def self.should_lookup_tiny_url?
    return false if cached?
    case env
    when "production" then return true
    when "staging" then return true
    else return false
    end
    false
    end

    View full-size slide

  72. module
    def self.should_lookup_tiny_url?
    return false if cached?
    case env
    when "production" then return true
    when "staging" then return true
    else return false
    end
    false
    end

    View full-size slide

  73. module
    def self.should_lookup_tiny_url?
    return false if cached?
    ["production", "staging"].include? env
    end

    View full-size slide

  74. @@lookup_tiny_urls = {}
    def self.shorten(url)
    @url = url
    # ...
    end
    def self.cached?
    !!@@lookup_tiny_urls[@url]
    end
    module

    View full-size slide

  75. !!@@lookup_tiny_urls[@url]
    module

    View full-size slide

  76. This could be
    dangerous...

    View full-size slide

  77. module
    module Tinyurl
    # ~75 lines of code
    end

    View full-size slide

  78. Take that you
    filthy scum...

    View full-size slide

  79. xp 062
    achievement
    unlocked

    View full-size slide

  80. xp
    class TidbitsController < ApplicationController
    def share_by_email_or_sms
    # ~50 LOC
    end
    # ~450 LOC
    end
    062

    View full-size slide

  81. xp
    class TidbitsController < ApplicationController
    def share_by_email_or_sms
    # ~50 LOC
    end
    # ~450 LOC
    end
    062
    controller

    View full-size slide

  82. xp 062
    def share_by_email_or_sms
    # ...
    unless invalid_name
    # ...
    else
    # ...
    end
    end
    controller

    View full-size slide

  83. xp 064
    def share_by_email_or_sms
    # ...
    unless invalid_name
    # ...
    else
    # ...
    end
    end
    controller

    View full-size slide

  84. xp
    def share_by_email_or_sms
    # ...
    unless invalid_name
    # ...
    else
    # ...
    end
    end
    064
    controller

    View full-size slide

  85. xp 064
    controller
    def share_by_email_or_sms
    # ...
    unless invalid_name
    # ...
    else
    # ...
    end
    end

    View full-size slide

  86. xp 066
    controller
    def share_by_email_or_sms
    # ...
    unless invalid_name
    # ...
    else
    # ...
    end
    end

    View full-size slide

  87. xp 066
    name = params[:name]
    if name && name.length > 40
    invalid_name = true
    else
    # ...
    end
    controller

    View full-size slide

  88. xp 070
    name = params[:name]
    if name && name.length > 40
    invalid_name = true
    else
    # ...
    end
    controller

    View full-size slide

  89. xp
    NAME=$(ruby -e "40.times { print 'x' }")
    curl -XPOST $URL \
    --data "emails=$EMAILS&name=$NAME"
    070

    View full-size slide

  90. xp
    HTTP/1.1 400 Bad Request
    {
    "error": "Invalid name."
    }
    070

    View full-size slide

  91. HTTP/1.1 400 Bad Request
    {
    "error": "Invalid name."
    }

    View full-size slide

  92. HTTP/1.1 400 Bad Request
    {
    "error": "Invalid name."
    }
    1 new message

    View full-size slide

  93. xp
    if name && name.length > 40
    invalid_name = true
    end
    controller 134

    View full-size slide

  94. xp
    if name && name.length > 40
    # ...
    end
    Gossip::Sharing.send_to_recipients(params)
    controller 134

    View full-size slide

  95. xp
    controller
    if name && name.length > 40
    # ...
    end
    Gossip::Sharing.send_to_recipients(params)
    unless invalid_name
    # ...
    else
    halt 400, {error: "Invalid name."}.to_json
    end
    134

    View full-size slide

  96. It is dark...

    View full-size slide

  97. xp
    name = params[:name]
    if name && name.length > 40
    invalid_name = true
    end
    controller 134

    View full-size slide

  98. xp
    curl -XPOST $URL \
    --data "emails=$EMAILS"
    134

    View full-size slide

  99. xp 134
    HTTP/1.1 400 Bad Request
    {
    "error":
    }

    View full-size slide

  100. xp 134
    HTTP/1.1 400 Bad Request
    {
    "error":
    "They have already been told."
    }

    View full-size slide

  101. xp
    HTTP/1.1 400 Bad Request
    {
    "error":
    "They have already been told."
    }
    142

    View full-size slide

  102. This could be
    dangerous...

    View full-size slide

  103. xp
    module Sharing
    # ~75 lines of code
    end
    142

    View full-size slide

  104. xp
    module
    module Sharing
    # ~75 lines of code
    end
    142

    View full-size slide

  105. xp
    module
    module Sharing
    def self.send_to_recipients(params)
    # ...
    end
    end
    142

    View full-size slide

  106. xp
    # Sends a params[:message] to a set of
    # params[:email_recipients] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module 142

    View full-size slide

  107. xp
    # Sends a params[:message] to a set of
    # params[:email_recipients] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module 142

    View full-size slide

  108. xp 142
    # Sends a params[:sms] to a set of
    # params[:email_recipients] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  109. xp 144
    # Sends a params[:sms] to a set of
    # params[:email_recipients] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  110. xp
    # Sends a params[:sms] to a set of
    # params[:email_recipients] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    144
    module

    View full-size slide

  111. xp 144
    # Sends a params[:sms] to a set of
    # params[:email] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  112. xp 146
    # Sends a params[:sms] to a set of
    # params[:email] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  113. xp
    # Sends a params[:sms] to a set of
    # params[:email] and
    # params[:sms_recipients]
    def self.send_to_recipients(params)
    # ...
    end
    146
    module

    View full-size slide

  114. xp 146
    # Sends a params[:sms] to a set of
    # params[:email] and
    # params[:numbers]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  115. xp 148
    # Sends a params[:sms] to a set of
    # params[:email] and
    # params[:numbers]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  116. xp
    # Sends a params[:sms] to a set of
    # params[:email] and params[:numbers]
    def self.send_to_recipients(params)
    # ...
    end
    148
    module

    View full-size slide

  117. xp 148
    # Sends a params[:sms] to a set of
    # params[:email] and params[:numbers]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  118. xp 150
    # Sends a params[:sms] to a set of
    # params[:email] and params[:numbers]
    def self.send_to_recipients(params)
    # ...
    end
    module

    View full-size slide

  119. xp
    # Sends params[:sms] to params[:numbers]
    # and a templated email to params[:email]
    def self.send_to_recipients(params)
    # ...
    end
    module 150

    View full-size slide

  120. xp
    def self.send_to_recipients(params)
    # ...
    end
    module 150

    View full-size slide

  121. xp
    module 150
    if params[:message]
    params[:sms].strip!
    params[:sms].squeeze!(" ")
    end

    View full-size slide

  122. xp 150
    module
    if params[:message]
    params[:sms].strip!
    params[:sms].squeeze!(" ")
    end

    View full-size slide

  123. xp 151
    module
    if params[:message]
    params[:sms].strip!
    params[:sms].squeeze!(" ")
    end

    View full-size slide

  124. xp 151
    params[:name].strip!
    params[:name].squeeze!(" ")
    module

    View full-size slide

  125. xp 153
    params[:name].strip!
    params[:name].squeeze!(" ")
    module

    View full-size slide

  126. xp 153
    params[:name].strip!
    params[:name].squeeze!(" ")
    if params[:name].length > 41
    return false
    end
    module

    View full-size slide

  127. xp 161
    params[:name].strip!
    params[:name].squeeze!(" ")
    if params[:name].length > 41
    return false
    end
    module

    View full-size slide

  128. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    # lots of stuff
    unless stuff?
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    send_to_sms(r, params)
    end
    # more stuff
    end
    end
    module 161

    View full-size slide

  129. xp 289
    high score

    View full-size slide

  130. xp
    recipients = [emails, phone_numbers].flatten
    module 289

    View full-size slide

  131. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    end
    module 289

    View full-size slide

  132. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    end
    end
    module 289

    View full-size slide

  133. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    end
    end
    module 289

    View full-size slide

  134. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    send_to_sms(r, params)
    end
    end
    module 289

    View full-size slide

  135. xp
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    send_to_sms(r, params)
    end
    module 289

    View full-size slide

  136. xp
    module
    # Send email
    def self.send_to_email(address, params)
    # ...
    end
    289

    View full-size slide

  137. xp
    module
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    289

    View full-size slide

  138. xp
    module
    Alice has a baby
    and posts a picture.
    Bob tells Charlie about it
    Bob provides Charlie’s email
    289

    View full-size slide

  139. xp
    Story
    Alice has a baby
    and posts a picture.
    Bob tells Charlie about it
    Bob provides Charlie’s email
    289

    View full-size slide

  140. xp
    Story
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    289

    View full-size slide

  141. xp
    Module
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    289

    View full-size slide

  142. xp
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    module 289

    View full-size slide

  143. xp
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    module 305

    View full-size slide

  144. xp
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    # lots of stuff
    unless stuff?
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    send_to_sms(r, params)
    end
    # more stuff
    end
    end
    module 161

    View full-size slide

  145. xp
    sent = []
    recipients = [emails, phone_numbers].flatten
    recipients.each do |r|
    # lots of stuff
    unless stuff?
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    if send_to_email(r, params)
    sent << r
    end
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    if send_to_sms(r, params)
    sent << r
    end
    end
    # more stuff
    end
    end
    sent
    module 161

    View full-size slide

  146. xp
    def self.send_to_email(address, params)
    if tidbit.created_by.email
    Mailer.tidbit_tip(address, params).deliver
    end
    true
    end
    module 305

    View full-size slide

  147. xp
    if r =~ /^([^@\s,]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
    send_to_email(r, params)
    elsif r =~ /^\s*\+?[0-9[:space:]]+\s*$/
    send_to_sms(r, params)
    end
    module 305

    View full-size slide

  148. xp
    # Send SMS
    def self.send_to_sms(number, params)
    # ...
    end
    module 305

    View full-size slide

  149. xp
    # Send SMS
    def self.send_to_sms(number, params)
    # TODO: Send SMS here
    end
    module 305

    View full-size slide

  150. xp 561
    high score

    View full-size slide

  151. Fundamental
    Attribution Error

    View full-size slide

  152. TODO:
    Send sms here

    View full-size slide

  153. PLAYER 1 PLAYER 2

    View full-size slide

  154. PLAYER 1 PLAYER 2

    View full-size slide

  155. PLAYER 1 PLAYER 2
    cooperate cooperate

    View full-size slide

  156. PLAYER 1 PLAYER 2
    cooperate cooperate
    3 3

    View full-size slide

  157. PLAYER 1 PLAYER 2

    View full-size slide

  158. PLAYER 1 PLAYER 2
    Defect Defect

    View full-size slide

  159. PLAYER 1 PLAYER 2
    Defect Defect
    1 1

    View full-size slide

  160. PLAYER 1 PLAYER 2

    View full-size slide

  161. PLAYER 1 PLAYER 2
    Cooperate

    View full-size slide

  162. PLAYER 1 PLAYER 2
    Cooperate Defect

    View full-size slide

  163. PLAYER 1 PLAYER 2
    Cooperate Defect
    5

    View full-size slide

  164. PLAYER 1 PLAYER 2
    Cooperate Defect
    5

    View full-size slide

  165. PLAYER 1 PLAYER 2
    Cooperate Defect
    0 5

    View full-size slide

  166. Sucker’s Payoff

    View full-size slide

  167. PLAYER 1 PLAYER 2

    View full-size slide

  168. PLAYER 1 PLAYER 2
    Defect

    View full-size slide

  169. PLAYER 1 PLAYER 2
    Defect Defect

    View full-size slide

  170. PLAYER 1 PLAYER 2
    Defect Defect
    1
    1

    View full-size slide

  171. PLAYER 1 PLAYER 2

    View full-size slide

  172. PLAYER 1 PLAYER 2
    cooperate

    View full-size slide

  173. PLAYER 1 PLAYER 2
    Defect cooperate

    View full-size slide

  174. PLAYER 1 PLAYER 2
    Defect cooperate
    5

    View full-size slide

  175. PLAYER 1 PLAYER 2
    Defect cooperate
    5 0

    View full-size slide

  176. Always Defect

    View full-size slide

  177. Cooperate as long
    as possible

    View full-size slide

  178. The Evolution of
    Cooperation

    View full-size slide

  179. Sucker’s Payoff

    View full-size slide

  180. Credits
    Source Code
    Anonymous
    Pixel Bug Illustrations
    Persa Zula
    The Evolution of Cooperation
    Robert Axelrod
    The Prisoner’s Dilemma
    Game Theory 101

    View full-size slide

  181. katrina owen
    @kytrinyx
    jumpstart lab

    View full-size slide