Your SlideShare is downloading. ×
Nordic Ruby 2011
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Nordic Ruby 2011

3,217
views

Published on

Published in: Technology

1 Comment
3 Likes
Statistics
Notes
No Downloads
Views
Total Views
3,217
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
16
Comments
1
Likes
3
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Saturday, June 18, 2011
  • 2. Saturday, June 18, 2011
  • 3. bitcoin == con-currency?Saturday, June 18, 2011
  • 4. Saturday, June 18, 2011
  • 5. José! Me!Saturday, June 18, 2011
  • 6. WWFMD?Saturday, June 18, 2011
  • 7. Public Service AnnouncementsSaturday, June 18, 2011
  • 8. SIGSEGV is badSaturday, June 18, 2011
  • 9. neversaydieSaturday, June 18, 2011
  • 10. begin # something dangerous rescue NeverSayDie # fix memory endSaturday, June 18, 2011
  • 11. "Not working in production mode"Saturday, June 18, 2011
  • 12. DO NOT USE THIS SOFTWARESaturday, June 18, 2011
  • 13. ruby -wSaturday, June 18, 2011
  • 14. def hello x = Object.new # warning 10 + 10 endSaturday, June 18, 2011
  • 15. warning: assigned but unused variable - xSaturday, June 18, 2011
  • 16. How deprecation notices SHOULD be writtenSaturday, June 18, 2011
  • 17. class Foo def deprecated if $VERBOSE warn "hey bro, dont call this" end 10 end endSaturday, June 18, 2011
  • 18. RSpec ProblemSaturday, June 18, 2011
  • 19. warning: useless use of == in void contextSaturday, June 18, 2011
  • 20. it "passes" do 10.should == 10 11.should == 11 endSaturday, June 18, 2011
  • 21. def check(thing) end def deprecated check 10.should == 10 check 11.should == 10 endSaturday, June 18, 2011
  • 22. @tenderloveSaturday, June 18, 2011
  • 23. AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.Saturday, June 18, 2011
  • 24. Ruby Core TeamSaturday, June 18, 2011
  • 25. Rails Core TeamSaturday, June 18, 2011
  • 26. Saturday, June 18, 2011
  • 27. White GuySaturday, June 18, 2011
  • 28. Story about Geethika and pinochle, java, etcSaturday, June 18, 2011
  • 29. Story about Geethika and pinochle, java, etc Its TYRA!Saturday, June 18, 2011
  • 30. <3 <3 <3Saturday, June 18, 2011
  • 31. "Congratulations, you just made us not consider Rails for anything anymore despite our coders liking it."Saturday, June 18, 2011
  • 32. SWEDEN!Saturday, June 18, 2011
  • 33. IKEA!Saturday, June 18, 2011
  • 34. MEATBALLS!Saturday, June 18, 2011
  • 35. SWEDISH FISH!Saturday, June 18, 2011
  • 36. Made in Canada!Saturday, June 18, 2011
  • 37. Made in Canada!Saturday, June 18, 2011
  • 38. How do you catch such tiny fish?Saturday, June 18, 2011
  • 39. Will you share your Swedish Fish Fishing spot?Saturday, June 18, 2011
  • 40. Talk about Rails, Talk about work projects Mountain Dew and my Trail of TearsSaturday, June 18, 2011
  • 41. Legacy CodeSaturday, June 18, 2011
  • 42. What is Legacy Code?Saturday, June 18, 2011
  • 43. UntestedSaturday, June 18, 2011
  • 44. OldSaturday, June 18, 2011
  • 45. Maintainers are gone Not UnderstoodSaturday, June 18, 2011
  • 46. Importance of Legacy CodeSaturday, June 18, 2011
  • 47. Old code contains KnowledgeSaturday, June 18, 2011
  • 48. Solves Todays ProblemsSaturday, June 18, 2011
  • 49. All Legacy Code is Not EqualSaturday, June 18, 2011
  • 50. Tenderlove Tear FormulaSaturday, June 18, 2011
  • 51. Code Burden Tears TimeSaturday, June 18, 2011
  • 52. Tears cried at time TSaturday, June 18, 2011
  • 53. Volume at time TSaturday, June 18, 2011
  • 54. Last WeekSaturday, June 18, 2011
  • 55. I LOVE hacking old codeSaturday, June 18, 2011
  • 56. TechniquesSaturday, June 18, 2011
  • 57. Techniques Universal Testing ExtendingSaturday, June 18, 2011
  • 58. UniversalSaturday, June 18, 2011
  • 59. Liskov substitution principleSaturday, June 18, 2011
  • 60. A subclass can be used in place of its superclassSaturday, June 18, 2011
  • 61. Object Animal PersonSaturday, June 18, 2011
  • 62. class Animal end class Person < Animal endSaturday, June 18, 2011
  • 63. def leg_count(animal) animal.legs end def account_number(person) person.account_number endSaturday, June 18, 2011
  • 64. Single Responsibility PrincipalSaturday, June 18, 2011
  • 65. Each class has one and only one responsibilitySaturday, June 18, 2011
  • 66. Each class has one reason to changeSaturday, June 18, 2011
  • 67. Method ExtractionSaturday, June 18, 2011
  • 68. class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 69. class WebClient def get(url) url = URI.parse url http_get end private def http_get Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 70. I dont like it, but it helps us to class WebClient reason def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • 71. Object#extendSaturday, June 18, 2011
  • 72. class Foo def metaclass class << self; self; end end end x = Foo.new p x.metaclass.ancestors x.extend(Module.new { }) p x.metaclass.ancestorsSaturday, June 18, 2011
  • 73. [Foo, Object, Kernel, BasicObject] [#<Module:0x81c98>, Foo, Object, Kernel, BasicObject]Saturday, June 18, 2011
  • 74. Code SeamsSaturday, June 18, 2011
  • 75. TestingSaturday, June 18, 2011
  • 76. Load Path HackingSaturday, June 18, 2011
  • 77. $LOAD_PATHSaturday, June 18, 2011
  • 78. ruby -Ifoo script.rbSaturday, June 18, 2011
  • 79. require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 80. [aaron@higgins project (master)]$ find . . ./test ./test/lib ./test/lib/net ./test/lib/net/http.rb ./web.rbSaturday, June 18, 2011
  • 81. test/lib/net/http.rb module Net class HTTP def self.get(host, path) "hello world" end end endSaturday, June 18, 2011
  • 82. ruby -I test/lib web.rbSaturday, June 18, 2011
  • 83. require web require minitest/autorun class WebTest < MiniTest::Unit::TestCase def test_get client = WebClient.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • 84. RSpec and People dont know about -I test/unit will set your -I for you require File.expand_path( File.join(.., foo))Saturday, June 18, 2011
  • 85. Heavy HandedSaturday, June 18, 2011
  • 86. Good for Small APIsSaturday, June 18, 2011
  • 87. Constant HackingSaturday, June 18, 2011
  • 88. require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 89. class MyHTTP def self.get(host, path) "hello world" end end WebClient.const_set(:Net, Module.new) WebClient::Net.const_set(:HTTP, MyHTTP)Saturday, June 18, 2011
  • 90. class WebTest < MiniTest::Unit::TestCase def setup WebClient.const_set(:Net, Module.new) WebClient::Net.const_set(:HTTP, MyHTTP) end def teardown WebClient.send(:remove_const, :Net) end def test_get client = WebClient.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • 91. class WebClient def get(url) url = URI.parse url ::Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 92. Localized Still must changes to mock one class entire API Heavy HandedSaturday, June 18, 2011
  • 93. Subclass TestingSaturday, June 18, 2011
  • 94. class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • 95. require net/http class WebClient def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • 96. Class.newSaturday, June 18, 2011
  • 97. class WebTest < MiniTest::Unit::TestCase def test_get client = Class.new(WebClient) { def http_get(host, path) hello world end }.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • 98. Annoying ConstructorsSaturday, June 18, 2011
  • 99. Many parameters, class Column def initialize(name, default, sql_type = nil,dont care=about null true) some of them @name = name @sql_type = sql_type @null = null @limit = extract_limit(sql_type) @precision = extract_precision(sql_type) @scale = extract_scale(sql_type) @type = simplified_type(sql_type) @default = extract_default(default) @primary = nil @coder = nil end .... endSaturday, June 18, 2011
  • 100. Just Pass nilSaturday, June 18, 2011
  • 101. def test_type_cast_true c = Column.new(nil, 1, int) assert_equal t, @conn.type_cast(true, nil) assert_equal 1, @conn.type_cast(true, c) endSaturday, June 18, 2011
  • 102. Cant construct, but want to break dependencies Not ConstructibleSaturday, June 18, 2011
  • 103. Too hard to construct pool = ActiveRecord::Base.connection_poolSaturday, June 18, 2011
  • 104. pool = ActiveRecord::Base.connection_pool.dup pool.extend(Module.new { def checkin conn @checkins << conn conn.object_id end })Saturday, June 18, 2011
  • 105. Detecting ChangesSaturday, June 18, 2011
  • 106. Measure http_get class WebClient def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • 107. via Class.newSaturday, June 18, 2011
  • 108. def test_http_get_count call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 109. def test_http_get_count call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 110. Decide to call def test_http_get_count super or not call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 111. via Module.newSaturday, June 18, 2011
  • 112. def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 113. def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 114. def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • 115. ExtendingSaturday, June 18, 2011
  • 116. Huge Methods!Saturday, June 18, 2011
  • 117. def table_rows rows[table_name] = fixtures.map do |label, fixture| if model_class && model_class < ActiveRecord::Base reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to # Do not replace association name with association foreign key if they are named the same fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s if association.name.to_s != fk_name && value = row.delete(association.name.to_s) if association.options[:polymorphic] && value.sub!(/s*(([^)]*))s*$/, "") # support polymorphic belongs_to as "label (Type)" row[association.foreign_type] = $1 end row[fk_name] = ActiveRecord::Fixtures.identify(value) end when :has_and_belongs_to_many if (targets = row.delete(association.name.to_s)) targets = targets.is_a?(Array) ? targets : targets.split(/s*,s*/) table_name = association.options[:join_table] rows[table_name].concat targets.map { |target| { association.foreign_key => row[primary_key_name], association.association_foreign_key => ActiveRecord::Fixtures.identify (target) } } end end end end row end rows endSaturday, June 18, 2011
  • 118. Extract MethodsSaturday, June 18, 2011
  • 119. def belongs_to_row(association, row) # Do not replace association name with association foreign key if they are named the same fk_name = (association.options[:foreign_key] || "# {association.name}_id").to_s if association.name.to_s != fk_name && value = row.delete (association.name.to_s) if association.options[:polymorphic] && value.sub!(/s*(([^)] *))s*$/, "") # support polymorphic belongs_to as "label (Type)" row[association.foreign_type] = $1 end row[fk_name] = ActiveRecord::Fixtures.identify(value) endSaturday, June 18, 2011
  • 120. def habtm_row(association, row) if (targets = row.delete(association.name.to_s)) targets = targets.is_a?(Array) ? targets : targets.split(/s*, s*/) table_name = association.options[:join_table] rows[table_name].concat targets.map { |target| { association.foreign_key => row [primary_key_name], association.association_foreign_key => ActiveRecord::Fixtures.identify(target) } } end endSaturday, June 18, 2011
  • 121. def table_rows rows[table_name] = fixtures.map do |label, fixture| row = fixture.to_hash if model_class && model_class < ActiveRecord::Base # If STI is used, find the correct subclass for association reflection reflection_class = if row.include?(inheritance_column_name) row[inheritance_column_name].constantize rescue model_class else model_class end reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to belongs_to_row(association, row) when :has_and_belongs_to_many habtm_row(association, row) end end end row end rows endSaturday, June 18, 2011
  • 122. Extract ObjectSaturday, June 18, 2011
  • 123. class RowFilter def rows fixtures.map do |label, fixture| row = fixture.to_hash if model_class && model_class < ActiveRecord::Base # If STI is used, find the correct subclass for association reflection reflection_class = if row.include?(inheritance_column_name) row[inheritance_column_name].constantize rescue model_class else model_class end reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to belongs_to_row(association, row) when :has_and_belongs_to_many habtm_row(association, row) end end end row end end endSaturday, June 18, 2011
  • 124. class RowFilter attr_reader :fixtures, :model_class def initialize(fixtures, model_class) @fixtures = fixtures @model_class = model_class end endSaturday, June 18, 2011
  • 125. def table_rows filter = RowFilter.new(fixtures, model_class) rows[table_name] = filter.rows rows endSaturday, June 18, 2011
  • 126. Huge Classes!Saturday, June 18, 2011
  • 127. Look at Method NamesSaturday, June 18, 2011
  • 128. Look at shared instance variablesSaturday, June 18, 2011
  • 129. Group Similar MethodsSaturday, June 18, 2011
  • 130. Use SRP to create a new classSaturday, June 18, 2011
  • 131. Then Delegate.Saturday, June 18, 2011
  • 132. All API callsSaturday, June 18, 2011
  • 133. Once we had extracted the HTTP class WebClient methods to their own functions, could def get(url) reason about HTTP url = URI.parse url api. http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • 134. class WebClient def initialize(client = Net::HTTP) @client = client end def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) @client.get(host, path) end endSaturday, June 18, 2011
  • 135. class TestHTTP < Struct.new(:data) def get(host, path) data[[host, path]] end endSaturday, June 18, 2011
  • 136. class WebTest < Test::Unit::TestCase def test_get_home mockhttp = TestHTTP.new({ [localhost, /~aaron/] => hello }) wc = WebClient.new mockhttp assert_equal hello, wc.get(http://localhost/~aaron/) end endSaturday, June 18, 2011
  • 137. We define expectationsSaturday, June 18, 2011
  • 138. Not Bound to HTTPSaturday, June 18, 2011
  • 139. Legacy code can make you crySaturday, June 18, 2011
  • 140. But it doesnt have toSaturday, June 18, 2011
  • 141. Dont be afraid!Saturday, June 18, 2011
  • 142. Ruby is your mocking frameworkSaturday, June 18, 2011
  • 143. Credits & More InfoSaturday, June 18, 2011
  • 144. Open Questions?Saturday, June 18, 2011
  • 145. Do you like mocking / stubbing?Saturday, June 18, 2011
  • 146. How do these testing tools impact your API?Saturday, June 18, 2011
  • 147. Do you like hearts?Saturday, June 18, 2011
  • 148. How about kittens?Saturday, June 18, 2011
  • 149. <3 <3 <3Saturday, June 18, 2011

×