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

The Case of the Vanished Variable – A Ruby Mystery Story

Nadia Odunayo
December 08, 2022
73

The Case of the Vanished Variable – A Ruby Mystery Story

After a stressful couple of days at work, Deirdre Bug is looking forward to a quiet evening in. But her plans are thwarted when the phone rings. “I know I’m the last person you want to hear from…but...I need your help!” Follow Deirdre as she embarks on an adventure that features a looming Demo Day with serious prize money up for grabs, a trip inside the walls of one of the Ruby community’s most revered institutions, and some broken code that appears to be much more simple than meets the eye.

Nadia Odunayo

December 08, 2022
Tweet

Transcript

  1. Jenny • 29 years old • Ruby developer • Rails

    obsessed 👱 • Betrayed her best friend
  2. Incubator • Help Ruby’s image • Startup ideas • $500k

    prize • Jenny’s team in fi nal two RIP
  3. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  4. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  5. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  6. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  7. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  8. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  9. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  10. @award_count = 0 def self.award_count @award_count end
 
 def self.assign!

    @award_count += 1 end end award_a.rb class AwardA < Grant
  11. @award_count = 0 def self.award_count @award_count end
 
 def self.assign!

    @award_count += 1 end end award_b.rb class AwardB < Grant
  12. @award_count = 0 def self.award_count @award_count end
 
 def self.assign!

    @award_count += 1 end end award_c.rb class AwardC < Grant
  13. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  14. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  15. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  16. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  17. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  18. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  19. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  20. class Grant
 MAX_GRANTS = 100 @award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  21. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 300 Awards left to assign: -200 ERROR: Maximum number of grants exceeded!
  22. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 300 Awards left to assign: -200 ERROR: Maximum number of grants exceeded!
  23. class AwardA < Grant @award_count = 0 … end class

    AwardB < Grant @award_count = 0 … end
  24. class AwardA < Grant @award_count = 0 … end class

    AwardB < Grant @award_count = 0 … end class AwardC < Grant @award_count = 0 … end
  25. class AwardA < Grant @award_count = 0 … end class

    AwardB < Grant @award_count = 0 … end class AwardC < Grant @award_count = 0 … end class Grant
 MAX_GRANTS = 100 @award_count = 0 … end
  26. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  27. class AwardA < Grant @award_a_count = 0 def self.award_count @award_a_count

    end
 
 def self.assign! @award_a_count += 1 end end award_a.rb
  28. class AwardA < Grant @award_a_count = 0 def self.award_count @award_a_count

    end
 
 def self.assign! @award_a_count += 1 end end award_a.rb
  29. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 300 Awards left to assign: -200 ERROR: Maximum number of grants exceeded!
  30. $

  31. $

  32. c c c c c G G G G G

    @ @ @ @ @ @ @ @ @ @ @ @ = d d d s s s s .a a a a a a a a a a a @ @ @ @ @ @ @ @ @ @ @ @ e e e e e e
  33. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 100 Awards left to assign: 0 SUCCESS: All awards assigned!
  34. 🕵 You mean class instance variables! 👱 No, class variables!

    🕵 You don’t mean class instance variables?
  35. class AwardA < Grant @award_count = 0 def self.award_count @award_count

    end
 
 def self.assign! @award_count += 1 end end award_a.rb
  36. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end award_a.rb
  37. class Grant
 MAX_GRANTS = 100 def self.award_count AwardA.award_count +
 AwardB.award_count

    +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  38. jenny:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 100 Awards left to assign: 0 SUCCESS: All awards assigned!
  39. class Grant
 MAX_GRANTS = 100 def self.award_count AwardA.award_count +
 AwardB.award_count

    +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  40. class Grant
 MAX_GRANTS = 100 @@award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  41. class Grant
 MAX_GRANTS = 100 @@award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  42. jenny:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 300 Awards left to assign: -200 ERROR: Maximum number of grants exceeded!
  43. He was trying to fi nd a quiet corner to

    take a personal call. 🧑🦱
  44. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end
  45. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end
  46. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end 🕵
  47. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end Those class variables look suspect… 🕵
  48. deebug:vanished_variable/ $ pry [1] pry(main)> class Grant [1] pry(main)* @@type

    = “Grant” [1] pry(main)* def self.type [1] pry(main)* @@type [1] pry(main)* end end [1] pry(main)* => :type [2] pry(main)> Grant.type => “Grant”
  49. [2] pry(main)> Grant.type => “Grant” [3] pry(main)> class AwardA <

    Grant [3] pry(main)* @@type = “A” [3] pry(main)* def self.type [3] pry(main)* @@type [3] pry(main)* end end [3] pry(main)* => :type [4] pry(main)>
  50. [3] pry(main)* def self.type [3] pry(main)* @@type [3] pry(main)* end

    end [3] pry(main)* => :type [5] pry(main)> Grant.type => “A” [4] pry(main)> AwardA.type => “A”
  51. [6] pry(main)> [7] pry(main)> Grant.superclass => Object [8] pry(main)> class

    Object [8] pry(main)* @@type = “Object” [8] pry(main)* def self.type [8] pry(main)* @@type [8] pry(main)* end end [8] pry(main)* => :type
  52. [8] pry(main)* def self.type [8] pry(main)* @@type [8] pry(main)* end

    end [8] pry(main)* => :type [10] pry(main)> [9] pry(main)> Object.type => “Object”
  53. [8] pry(main)* def self.type [8] pry(main)* @@type [8] pry(main)* end

    end [8] pry(main)* => :type [10] pry(main)> Grant.type [9] pry(main)> Object.type => “Object” RuntimeError: class variable @@type of Grant is overtaken by Object from (pry):4:in `type' [11] pry(main)>
  54. [10] pry(main)> Grant.type [9] pry(main)> Object.type => “Object” RuntimeError: class

    variable @@type of Grant is overtaken by Object from (pry):4:in `type' [11] pry(main)>
  55. [10] pry(main)> Grant.type [9] pry(main)> Object.type => “Object” RuntimeError: class

    variable @@type of Grant is overtaken by Object from (pry):4:in `type' [11] pry(main)> AwardA.type RuntimeError: class variable @@type of Grant is overtaken by Object from (pry):11:in `type' [12] pry(main)>
  56. @@type = “A” @@type = “A” class Grant class AwardA

    inherits from inherits from class Object
  57. @@type = “A” @@type = “A” class Grant class AwardA

    inherits from inherits from class Object @@type = “Object”
  58. class Grant class AwardA inherits from inherits from class Object

    @@type = “Object” @@type = RuntimeError @@type = RuntimeError
  59. [12] pry(main)> [13] pry(main)> Grant.ancestors => [Grant, Object, PP::ObjectMixin, Kernel,

    BasicObject] [14] pry(main)> class BasicObject [14] pry(main)* @@type = “Basic” [14] pry(main)* def self.type [14] pry(main)* @@type [14] pry(main)* end end [14] pry(main)* => :type [15] pry(main)>
  60. [14] pry(main)> class BasicObject [14] pry(main)* @@type = “Basic” [14]

    pry(main)* def self.type [14] pry(main)* @@type [14] pry(main)* end end [14] pry(main)* => :type [15] pry(main)>
  61. [14] pry(main)> class BasicObject [14] pry(main)* @@type = “Basic” [14]

    pry(main)* def self.type [14] pry(main)* @@type [14] pry(main)* end end [14] pry(main)* => :type [15] pry(main)> Grant.type RuntimeError: class variable @@type of Grant is overtaken by BasicObject from (pry):4:in `type' [16] pry(main)>
  62. RClass Class variables @@award_count = 0 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC class AwardA < Grant @@award_count = 0 … end
  63. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end award_a.rb
  64. RClass Class variables @@award_count = 0 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC 50.times do AwardA.assign! end
  65. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC 50.times do AwardA.assign! end
  66. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC 50.times do AwardA.assign! end
  67. class AwardA < Grant @@award_count = 0 def self.award_count @@award_count

    end
 
 def self.assign! @@award_count += 1 end end award_a.rb
  68. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 50
  69. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 50
  70. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 50 AwardB.award_count = 50 AwardC.award_count = 50
  71. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 50 AwardB.award_count = 50 AwardC.award_count = 50
  72. RClass Class variables @@award_count = 50 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC 30.times do AwardB.assign! end
  73. RClass Class variables @@award_count = 80 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 80 AwardB.award_count = 80 AwardC.award_count = 80
  74. RClass Class variables @@award_count = 80 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 80 AwardB.award_count = 80 AwardC.award_count = 80
  75. RClass Class variables @@award_count = 80 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC 20.times do AwardC.assign! end
  76. RClass Class variables @@award_count = 100 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 100 AwardB.award_count = 100 AwardC.award_count = 100
  77. RClass Class variables @@award_count = 100 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 100 AwardB.award_count = 100 AwardC.award_count = 100
  78. class Grant
 MAX_GRANTS = 100 @@award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  79. class Grant
 MAX_GRANTS = 100 @@award_count = 0 def self.award_count

    AwardA.award_count +
 AwardB.award_count +
 AwardC.award_count end
 
 def self.awards_remaining MAX_GRANTS - self.award_count end end grant.rb
  80. RClass Class variables @@award_count = 100 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 100 AwardB.award_count = 100 AwardC.award_count = 100
  81. RClass Class variables @@award_count = 100 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 100 AwardB.award_count = 100 AwardC.award_count = 100
  82. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed…
  83. alex:rip_grant_program/ $ ruby grant_awards.rb Awarding 50 grants of type A…

    Awarding 30 grants of type B… Awarding 20 grants of type C… Checking if prize redraw is needed… Total number of grants awarded so far… 300 Awards left to assign: -200 ERROR: Maximum number of grants exceeded!
  84. RClass Class variables @@award_count = 100 : Grant RClass: AwardB

    RClass: AwardA RClass: AwardC AwardA.award_count = 100 AwardB.award_count = 100 AwardC.award_count = 100
  85. [14] pry(main)> class BasicObject [14] pry(main)* @@type = “Basic” [14]

    pry(main)* def self.type [14] pry(main)* @@type [14] pry(main)* end end [14] pry(main)* => :type [15] pry(main)>
  86. [14] pry(main)> class BasicObject [14] pry(main)* @@type = “Basic” [14]

    pry(main)* def self.type [14] pry(main)* @@type [14] pry(main)* end end [14] pry(main)* => :type [15] pry(main)> Grant.type RuntimeError: class variable @@type of Grant is overtaken by BasicObject from (pry):4:in `type' [16] pry(main)>
  87. The RIP Grant Program won the $500k prize and continues

    to run successfully, headed up by Jenny…