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

Code to Joy

avdi
September 15, 2012

Code to Joy

A random walk through the Ruby language and standard library, highlighting some tools and idioms that make me happy.

avdi

September 15, 2012
Tweet

More Decks by avdi

Other Decks in Programming

Transcript

  1. Code to Joy
    Avdi Grimm
    ShipRise
    GoGaRuCo 2012
    Avdi Grimm (ShipRise) Code to Joy GoGaRuCo 2012 1 / 50

    View Slide

  2. Code to Joy Introduction
    Introduction
    These are a few of my favorite things.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 2 / 50

    View Slide

  3. Code to Joy Introduction
    My Job is Awesome
    • My job is awesome
    Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

    View Slide

  4. Code to Joy Introduction
    My Job is Awesome
    • My job is awesome
    • Remotely pairing with many different people
    Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

    View Slide

  5. Code to Joy Introduction
    My Job is Awesome
    • My job is awesome
    • Remotely pairing with many different people
    • Different levels of knowledge, different problems to solve
    Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

    View Slide

  6. Code to Joy Introduction
    My Job is Awesome
    • My job is awesome
    • Remotely pairing with many different people
    • Different levels of knowledge, different problems to solve
    • ”That’s so cool, I didn’t know you could do that”
    Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

    View Slide

  7. Code to Joy Introduction
    Ruby is Awesome
    Ruby is designed to make programmers happy.
    — Matz
    It still finds ways to make me smile after all these years.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 4 / 50

    View Slide

  8. Code to Joy Introduction
    Postcards are Awesome
    • Work in progress: Confident Ruby
    Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

    View Slide

  9. Code to Joy Introduction
    Postcards are Awesome
    • Work in progress: Confident Ruby
    • ”Pay with a postcard”
    Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

    View Slide

  10. Code to Joy Introduction
    Postcards are Awesome
    • Work in progress: Confident Ruby
    • ”Pay with a postcard”
    • Postcards make me happy!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

    View Slide

  11. Code to Joy Introduction
    The Plan
    • A random walk through the Ruby language and standard
    library. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

    View Slide

  12. Code to Joy Introduction
    The Plan
    • A random walk through the Ruby language and standard
    library. . .
    • . . . stopping in at some of my favorite idioms and tools. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

    View Slide

  13. Code to Joy Introduction
    The Plan
    • A random walk through the Ruby language and standard
    library. . .
    • . . . stopping in at some of my favorite idioms and tools. . .
    • . . . and around the world, in postcards!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

    View Slide

  14. Code to Joy Splats
    Splats
    Avdi Grimm (ShipRise) GoGaRuCo 2012 7 / 50

    View Slide

  15. Code to Joy Splats
    Simple Destructuring
    spawn( ’true’ )
    pid, status = *Process.wait2
    pid # => 9159
    status # => #
    Avdi Grimm (ShipRise) GoGaRuCo 2012 8 / 50

    View Slide

  16. Code to Joy Splats
    Implicit splat
    spawn( ’true’ )
    pid, status = Process.wait2
    pid # => 16804
    status # => #
    Avdi Grimm (ShipRise) GoGaRuCo 2012 9 / 50

    View Slide

  17. Code to Joy Splats
    Multiple return values
    def send_request
    # ...
    code = 404
    message = "Not found"
    # ???
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 10 / 50

    View Slide

  18. Code to Joy Splats
    One client wants individual values
    code, message = send_request
    logger.info " #{ code } : #{ message } "
    Avdi Grimm (ShipRise) GoGaRuCo 2012 11 / 50

    View Slide

  19. Code to Joy Splats
    Another client wants an object
    response = send_request
    case response.code
    when 400..599 then handle_error(response)
    else
    # ...
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 12 / 50

    View Slide

  20. Code to Joy Splats
    cake.have && cake.eat
    Response = Struct.new( :code , :message )
    r = Response.new(404, "Not found" )
    # Attributes:
    r.code # => 404
    r.message # => "Not found"
    # Splat:
    code, msg = *r
    code # => 404
    msg # => "Not found"
    Avdi Grimm (ShipRise) GoGaRuCo 2012 13 / 50

    View Slide

  21. Code to Joy Splats
    One little problem
    Response = Struct.new( :code , :message )
    r = Response.new(404, "Not found" )
    code, msg = r # no splat
    code # => #
    msg # => nil
    Avdi Grimm (ShipRise) GoGaRuCo 2012 14 / 50

    View Slide

  22. Code to Joy Splats
    An implicitly splattable Struct
    Response = Struct.new( :code , :message ) do
    alias_method :to_ary , :to_a
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 15 / 50

    View Slide

  23. Code to Joy Splats
    An implicitly splattable Struct
    Response = Struct.new( :code , :message ) do
    alias_method :to_ary , :to_a
    end
    r = Response.new(404, "Not found" )
    code, msg = r # look ma, no splat!
    code # => 404
    msg # => "Not found"
    Avdi Grimm (ShipRise) GoGaRuCo 2012 15 / 50

    View Slide

  24. Code to Joy Splats
    Returning a splattable Struct
    def send_request
    # ...
    Response.new(code, message)
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 16 / 50

    View Slide

  25. Code to Joy Splats
    Splatting the Struct into component parts
    code, message = send_request
    logger.info " #{ code } : #{ message } "
    Avdi Grimm (ShipRise) GoGaRuCo 2012 17 / 50

    View Slide

  26. Code to Joy Splats
    Using the response Struct as-is
    response = send_request
    case response.code
    when 400..599 then handle_error(response)
    else
    # ...
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 18 / 50

    View Slide

  27. Code to Joy Splats
    Splats & Structs
    • Return multiple values from a method. . .
    • . . . *Or* a single result object. . .
    • . . . from the same line of code. Magic!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 19 / 50

    View Slide

  28. Code to Joy YAML::Store
    YAML::Store
    Avdi Grimm (ShipRise) GoGaRuCo 2012 20 / 50

    View Slide

  29. Code to Joy YAML::Store
    Persisting Posts
    require ’yaml/store’
    repo = YAML::Store.new( ’blog.yml’ )
    Post = Struct.new( :title , :body )
    repo.transaction do
    posts = repo[ :posts ] = []
    posts << Post.new( "F1rst Post!!!" , "FIRST" )
    posts << Post.new( "Hiatus" ,
    "This blog is on vacation" )
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 21 / 50

    View Slide

  30. Code to Joy YAML::Store
    The Persisted Data
    cat blog.yml
    ---
    :posts:
    - !ruby/struct:Post
    title: F1rst Post!!!
    body: FIRST
    - !ruby/struct:Post
    title: Hiatus
    body: This blog is on vacation
    Avdi Grimm (ShipRise) GoGaRuCo 2012 22 / 50

    View Slide

  31. Code to Joy YAML::Store
    Associations
    Post = Struct.new( :title , :body , :category )
    Category = Struct.new( :name )
    food = Category.new( :food )
    repo.transaction do
    posts = repo[ :posts ] = []
    posts << Post.new( "Cookie!!!" ,
    "C is for cookie!" , food)
    posts << Post.new( "Durian" ,
    "Stinky!" , food)
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 23 / 50

    View Slide

  32. Code to Joy YAML::Store
    Associations YAML
    ---
    :posts:
    - !ruby/struct:Post
    title: Cookie!!!
    body: C is for cookie!
    category: &8509480 !ruby/struct:Category
    name: :food
    - !ruby/struct:Post
    title: Durian
    body: Stinky!
    category: *8509480
    Avdi Grimm (ShipRise) GoGaRuCo 2012 24 / 50

    View Slide

  33. Code to Joy YAML::Store
    PStore
    • Drop-in replacement
    require ’pstore’
    2
    repo = PStore.new( ’blog.pstore’ )
    repo.transaction do
    4
    # ...
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 25 / 50

    View Slide

  34. Code to Joy YAML::Store
    PStore
    • Drop-in replacement
    require ’pstore’
    2
    repo = PStore.new( ’blog.pstore’ )
    repo.transaction do
    4
    # ...
    end
    • Faster
    Adding 1000 posts, with a transaction for each write:
    user system total real
    yaml 50.210000 0.210000 50.420000 ( 54.024277)
    pstore 3.290000 0.130000 3.420000 ( 10.887887)
    Avdi Grimm (ShipRise) GoGaRuCo 2012 25 / 50

    View Slide

  35. Code to Joy YAML::Store
    YAML#Store
    • Incredibly simple Hash-like persistence mechanism
    • Great for local command-line apps
    • Supports complex object trees
    • Oh yeah, one more thing. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 26 / 50

    View Slide

  36. Code to Joy YAML::Store
    YAML#Store
    • Incredibly simple Hash-like persistence mechanism
    • Great for local command-line apps
    • Supports complex object trees
    • Oh yeah, one more thing. . .
    • ZOMG NOSQL!!!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 26 / 50

    View Slide

  37. Code to Joy Enumerators
    Enumerators
    Avdi Grimm (ShipRise) GoGaRuCo 2012 27 / 50

    View Slide

  38. Code to Joy Enumerators
    Kernel#to_enum
    Convert any old method into an Enumerator
    def names
    yield ’Ylva’
    yield ’Brighid’
    yield ’Shifra’
    yield ’Yasmin’
    end
    e = to_enum( :names ) # => #
    e.to_a # => ["Ylva", "Brighid", "Shifra", "Yasmin"]
    Avdi Grimm (ShipRise) GoGaRuCo 2012 28 / 50

    View Slide

  39. Code to Joy Enumerators
    Searching for config files
    + project
    |-- .rutrc
    |-- file1
    |-- file2
    |-+ subproject |-- .rutrc
    |-- file3
    \-- ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 29 / 50

    View Slide

  40. Code to Joy Enumerators
    Pathname#ascend
    require ’pathname’
    Dir.chdir( ’/home/avdi/dev’ )
    Pathname.pwd.ascend do |dir|
    puts dir
    end
    /home/avdi/dev
    /home/avdi
    /home
    /
    Avdi Grimm (ShipRise) GoGaRuCo 2012 30 / 50

    View Slide

  41. Code to Joy Enumerators
    Searching upwards for config files
    require ’pathname’
    curdir = Pathname.pwd
    configs = curdir.to_enum( :ascend ).
    each_with_object([]){ |dir, files|
    config = (dir + ’.rutrc’ )
    files << config if config.file?
    }
    Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

    View Slide

  42. Code to Joy Enumerators
    Searching upwards for config files
    curdir = Pathname.pwd
    configs = curdir.to_enum(:ascend).
    each_with_object([]) { |dir, files|
    config = (dir + ’.rutrc’)
    files « config if config.file?
    }
    Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

    View Slide

  43. Code to Joy Enumerators
    Searching upwards for config files
    curdir = Pathname.pwd
    configs = curdir.to_enum(:ascend).
    each_with_object([]) { |dir, files|
    config = (dir + ’.rutrc’)
    files « config if config.file?
    }
    Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

    View Slide

  44. Code to Joy Enumerators
    Searching upwards for config files
    curdir = Pathname.pwd
    configs = curdir.to_enum(:ascend).
    each_with_object([]) { |dir, files|
    config = (dir + ’.rutrc’)
    files « config if config.file?
    }
    Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

    View Slide

  45. Code to Joy Enumerators
    Enumerator and #to_enum
    • Turn any method into an iterable series
    • Make all the power of Enumerator available to the series
    Avdi Grimm (ShipRise) GoGaRuCo 2012 32 / 50

    View Slide

  46. Code to Joy Break
    Give me a break
    Avdi Grimm (ShipRise) GoGaRuCo 2012 33 / 50

    View Slide

  47. Code to Joy Break
    break
    It breaks out of loops. Whoop-de-doo.
    jobs.each do |job|
    break if job == :terminate
    job.call
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 34 / 50

    View Slide

  48. Code to Joy Break
    break beyond iteration
    def names
    yield ’Ylva’
    yield ’Brighid’
    yield ’Shifra’
    yield ’Yasmin’
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

    View Slide

  49. Code to Joy Break
    break beyond iteration
    i = 0
    names do |name|
    puts name
    break if i >= 1 # that’s plenty!
    i += 1
    end
    Ylva
    Brighid
    Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

    View Slide

  50. Code to Joy Break
    break beyond iteration
    def names
    yield ’Ylva’
    yield ’Brighid’
    # ---- We stopped here! ----
    yield ’Shifra’
    yield ’Yasmin’
    end
    Without a return, throw, or raise.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

    View Slide

  51. Code to Joy Break
    break respects ensure blocks
    def names_with_last
    yield ’Ylva’
    yield ’Brighid’
    yield ’Shifra’
    yield ’Yasmin’
    ensure
    puts "Grimm"
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

    View Slide

  52. Code to Joy Break
    break respects ensure blocks
    i = 0
    names_with_last do |name|
    puts name
    break if i >= 1 # that’s plenty!
    i += 1
    end
    Ylva
    Brighid
    Grimm
    Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

    View Slide

  53. Code to Joy Break
    break respects ensure blocks
    def names_with_last
    yield ’Ylva’
    yield ’Brighid’
    # ---- We stopped here... ----
    yield ’Shifra’
    yield ’Yasmin’
    ensure
    # ...and jumped to here.
    puts "Grimm"
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

    View Slide

  54. Code to Joy Break
    break with a value
    What if we want to capture a name?
    result = nil
    result = names do |name|
    if name =~ /^S/
    result = name
    break
    end
    end
    result # => "Shifra"
    Avdi Grimm (ShipRise) GoGaRuCo 2012 37 / 50

    View Slide

  55. Code to Joy Break
    break with a value
    result = names do |name|
    break name if name =~ /^S/
    end
    result # => "Shifra"
    This effectively overrides the method’s return value.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 37 / 50

    View Slide

  56. Code to Joy Break
    Breaking from a #detect
    f = open( ’code-to-joy.org’ )
    result = f.lines.detect do |line|
    break "" if f.lineno >= 100
    line =~ /banana/
    end
    result # => ""
    Avdi Grimm (ShipRise) GoGaRuCo 2012 38 / 50

    View Slide

  57. Code to Joy Subclassing Module
    Subclassing Module
    Avdi Grimm (ShipRise) GoGaRuCo 2012 39 / 50

    View Slide

  58. Code to Joy Subclassing Module
    A simple RPG
    Race = Struct.new( :name , :strength )
    CharacterClass = Struct.new( :name , :charisma )
    Character = Struct.new( :name , :race , :char_class )
    human = Race.new( "Human" , 9)
    wizard = CharacterClass.new( "Tourist" , 3)
    player = Character.new( "Rhincewind" , human, wizard)
    Avdi Grimm (ShipRise) GoGaRuCo 2012 40 / 50

    View Slide

  59. Code to Joy Subclassing Module
    What we’d like
    Ideally, attributes would be delegated to either race or char_class.
    player.name # => "Rhincewind"
    player.strength # => 9
    player.charisma # => 3
    Avdi Grimm (ShipRise) GoGaRuCo 2012 41 / 50

    View Slide

  60. Code to Joy Subclassing Module
    Using Forwardable
    require ’forwardable’
    Character = Struct.new( :name , :race , :char_class ) do
    extend Forwardable
    def_delegators :race , :strength
    def_delegators :char_class , :charisma
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 42 / 50

    View Slide

  61. Code to Joy Subclassing Module
    Evolving with Forwardable
    Race = Struct.new( :name , :strength , :constitution )
    human = Race.new( "Human" , 9, 5)
    # ...
    Character = Struct.new( :name , :race , :char_class ) do
    extend Forwardable
    def_delegators :race , :strength , :constitution
    # ...
    end
    Every change has to be made twice.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 43 / 50

    View Slide

  62. Code to Joy Subclassing Module
    Using SimpleDelegator
    require ’delegate’
    class Character < SimpleDelegator
    def initialize(name, race, char_class)
    @name = name
    super(race)
    end
    # ...
    end
    Only one object supported.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 44 / 50

    View Slide

  63. Code to Joy Subclassing Module
    Subclassing Module
    class Delegate < Module
    def initialize(attribute)
    @attribute = attribute
    super() do
    # see next slide...
    end
    end
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  64. Code to Joy Subclassing Module
    Subclassing Module
    # ...
    define_method( :method_missing ) do
    |message, *args, &block|
    target = send(attribute)
    if target.respond_to?(message)
    target.public_send(message, *args, &block)
    else
    super(message, *args, &block)
    end
    end
    # ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  65. Code to Joy Subclassing Module
    Subclassing Module
    # ...
    define_method(:method_missing) do
    |message, *args, &block|
    target = send(attribute)
    if target.respond_to?(message)
    target.public_send(message, *args, &block)
    else
    super(message, *args, &block)
    end
    end
    # ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  66. Code to Joy Subclassing Module
    Subclassing Module
    # ...
    define_method(:method_missing) do
    |message, *args, &block|
    target = send(attribute)
    if target.respond_to?(message)
    target.public_send(message, *args, &block)
    else
    super(message, *args, &block)
    end
    end
    # ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  67. Code to Joy Subclassing Module
    Subclassing Module
    # ...
    define_method(:method_missing) do
    |message, *args, &block|
    target = send(attribute)
    if target.respond_to?(message)
    target.public_send(message, *args, &block)
    else
    super(message, *args, &block)
    end
    end
    # ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  68. Code to Joy Subclassing Module
    Subclassing Module
    # ...
    define_method(:method_missing) do
    |message, *args, &block|
    target = send(attribute)
    if target.respond_to?(message)
    target.public_send(message, *args, &block)
    else
    super(message, *args, &block)
    end
    end
    # ...
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  69. Code to Joy Subclassing Module
    Subclassing Module
    class Delegate < Module
    # ...
    def to_s
    "Delegate( #{ @attribute.inspect } )"
    end
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  70. Code to Joy Subclassing Module
    Subclassing Module
    Character = Struct.new( :name , :race , :char_class ) do
    include Delegate.new( :race )
    include Delegate.new( :char_class )
    end
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  71. Code to Joy Subclassing Module
    Subclassing Module
    player.class.ancestors # =>
    [Character,
    Delegate( :char_class ),
    Delegate( :race ),
    Struct, ...]
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  72. Code to Joy Subclassing Module
    Subclassing Module
    Race = Struct.new( :name , :strength )
    CharacterClass = Struct.new( :name , :charisma )
    # ...
    player = Character.new( "Rhincewind" , human, wizard)
    player.name # => "Rhincewind"
    player.strength # => 9
    player.charisma # => 3
    A chain of responsibility:
    1 self
    2 self.char_class
    3 self.race
    4 Other ancestors. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

    View Slide

  73. Code to Joy Subclassing Module
    Subclassing Module
    • Creates a new “kind” of module
    • Enables us to add state to the modules a class includes
    • Enabled us to implement a new type of message delegation in
    Ruby
    Avdi Grimm (ShipRise) GoGaRuCo 2012 46 / 50

    View Slide

  74. Code to Joy MINASWAN
    My Favorite Thing of All
    MINASWAN
    Avdi Grimm (ShipRise) GoGaRuCo 2012 47 / 50

    View Slide

  75. Code to Joy Conclusion
    Sometimes we get discouraged
    • Technical debt got you down?
    Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

    View Slide

  76. Code to Joy Conclusion
    Sometimes we get discouraged
    • Technical debt got you down?
    • Community drama bumming you out?
    Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

    View Slide

  77. Code to Joy Conclusion
    Sometimes we get discouraged
    • Technical debt got you down?
    • Community drama bumming you out?
    • If you’re blue, don’t know where to go to. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

    View Slide

  78. Code to Joy Conclusion
    Sometimes we get discouraged
    • Technical debt got you down?
    • Community drama bumming you out?
    • If you’re blue, don’t know where to go to. . .
    • . . . practice joyful coding
    Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

    View Slide

  79. Code to Joy Conclusion
    Sometimes we get discouraged
    • Technical debt got you down?
    • Community drama bumming you out?
    • If you’re blue, don’t know where to go to. . .
    • . . . practice joyful coding
    • How?
    Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

    View Slide

  80. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  81. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    • Shared code is joyful code
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  82. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    • Shared code is joyful code
    • If you want to feel good about your craft. . .
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  83. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    • Shared code is joyful code
    • If you want to feel good about your craft. . .
    • . . . give someone a “wow” moment.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  84. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    • Shared code is joyful code
    • If you want to feel good about your craft. . .
    • . . . give someone a “wow” moment.
    • Show one person something awesome.
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  85. Code to Joy Conclusion
    Defend your joy
    • There’s no metric for joyful code
    • Shared code is joyful code
    • If you want to feel good about your craft. . .
    • . . . give someone a “wow” moment.
    • Show one person something awesome.
    • I promise you’ll feel better!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

    View Slide

  86. Code to Joy Conclusion
    Thank You
    • Rate! http://spkr8.com/t/16041
    • Contact! [email protected]
    • Tweet! @avdi
    • Read! http://confidentruby.com
    • 20% off: GOGARUCO2012
    • . . . or send me a postcard!
    Avdi Grimm (ShipRise) GoGaRuCo 2012 50 / 50

    View Slide