Refactoring Ruby Code

2,551 views

Published on

Refactoring Ruby code talk given @ Oxente Rails 2010

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,551
On SlideShare
0
From Embeds
0
Number of Embeds
52
Actions
Shares
0
Downloads
39
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

Refactoring Ruby Code

  1. 1. Refatorando Código Ruby @caike http://caikesouza.com caike@envylabs.com
  2. 2. www.envylabs.com
  3. 3. Métodos Ágeis
  4. 4. Testes
  5. 5. (Anti-)Patterns
  6. 6. Software Craftsmanship
  7. 7. "Any fool can write code that a computer can understand. Good programmers write code that humans can understand" (Martin Fowler)
  8. 8. Refatorar é ...
  9. 9. Limpar a casa sem mudar a fachada
  10. 10. Algumas razões
  11. 11. Design
  12. 12. Responder a mudanças
  13. 13. Entregas Constantes
  14. 14. Waterfall Jan Feb Mar Apr May Jun Jul Cost of Maintenance Extreme Programming Explained: Embrace Change Addison Wesley, 2000
  15. 15. XP Jan Feb Mar Apr May Jun Jul Cost of Maintenance Extreme Programming Explained: Embrace Change Addison Wesley, 2000
  16. 16. Quando ?
  17. 17. novas features
  18. 18. bugs
  19. 19. Débito Técnico
  20. 20. Code Reviews
  21. 21. “The great thing about programming is pretty much everyone's code is shit. Writing software is hard, so it's no problem finding dogs in someone's stuff” (Zed Shaw)
  22. 22. exemplos.rb
  23. 23. managers = [] employees.each do |e| managers << e if e.is_manager? end
  24. 24. managers = [] employees.each do |e| managers << e if e.is_manager? end
  25. 25. Replace Loop with Closure Method
  26. 26. managers = [] employees.each do |e| managers << e if e.is_manager? end
  27. 27. managers = employees. select { |e| e.is_manager? }
  28. 28. class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 end end
  29. 29. class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 end end
  30. 30. Introduce Explaining Variable
  31. 31. class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 end end
  32. 32. class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 end end
  33. 33. class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 end end
  34. 34. Replace Temp With Query
  35. 35. class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 end end
  36. 36. class Movie def initialize(stars) @stars = stars end def recommended? rating >= 8 end def rating (@stars > 5) ? 8 : 1 end end
  37. 37. OMG OMG OMG OMG OMG
  38. 38. class Movie def recommended? rating >= 8 end def rating (@stars > 5) ? 8 : 1 end end
  39. 39. class Movie def recommended? rating >= 8 end def rating more_than_five_stars? ? 8 : 1 end def more_than_five_stars? @stars > 5 end end
  40. 40. Inline Method
  41. 41. class Movie def initialize...end def recommended? rating >= 8 end def rating more_than_five_stars? ? 8 : 1 end def more_than_five_stars? @stars > 5 end end
  42. 42. class Movie def initialize...end def recommended? rating >= 8 end def rating @stars > 5 ? 8 : 1 end end
  43. 43. mock = mock('user') expectation = mock.expects(:find) expectation.with("1") expectation.returns([])
  44. 44. mock = mock('user') expectation = mock.expects(:find) expectation.with("1") expectation.returns([])
  45. 45. Replace Temp With Chain
  46. 46. mock = mock('user') expectation = mock.expects(:find) expectation.with("1") expectation.returns([])
  47. 47. mock = mock('user') mock.expects(:find).with("1"). returns([])
  48. 48. Command vs. Query
  49. 49. def expects ... self end def with ... self end def returns ... self end
  50. 50. def charge(amount, card_number) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close end end
  51. 51. def charge(amount, card_number) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close end end
  52. 52. Extract Surrounding Method
  53. 53. def charge(amount, ccnumber) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close end end
  54. 54. def charge(amount, card_number) connect do |conn| conn.send(amount, card_number) end end
  55. 55. def connect begin conn = CC_Charger_Server.connect(...) yield conn rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close end end
  56. 56. def body_fat_percentage(name, age, height, weight, metric_system) ... end
  57. 57. body_fat_percentage("fred", 30, 1.82, 90, 1) body_fat_percentage("joe", 32, 6, 220, 2)
  58. 58. body_fat_percentage("fred", 30, 1.82, 90, 1) body_fat_percentage("joe", 32, 6, 220, 2)
  59. 59. Introduce Named Parameter
  60. 60. body_fat_percentage("fred", 30, 1.82, 90, 1) body_fat_percentage("joe", 32, 6, 220, 2)
  61. 61. body_fat_percentage("fred", :age => 30, :height => 1.82, :weight => 90, MetricSystem::METERS_KG) body_fat_percentage("joe", :age => 32, :height => 6, :weight => 220, MetricSystem::FEET_LB)
  62. 62. def body_fat_percentage(name, age, height, weight, metric_system) ... end
  63. 63. def body_fat_percentage(name, params={}) # params[:age] # params[:height] # params[:weight] # params[:metric_system] end
  64. 64. user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
  65. 65. user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
  66. 66. Replace Magic Number with Symbolic Constant
  67. 67. user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
  68. 68. CONTACTS_PER_PAGE = 15 user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || CONTACTS_PER_PAGE)
  69. 69. class MountainBike def price ... end end MountainBike.new(:type => :rigid, ...) MountainBike.new(:type => :front_suspension, ...) MountainBike.new(:type => :full_suspension, ...)
  70. 70. def price if @type_code == :rigid (1 + @comission) * @base_price end if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_price end if @type_code == :full_suspension (1 + @comission) * @base_price+ @front_suspension_price + @rear_suspension_price end end
  71. 71. def price if @type_code == :rigid (1 + @comission) * @base_price end if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_price end if @type_code == :full_suspension (1 + @comission) * @base_price+ @front_suspension_price + @rear_suspension_price end if @type_code == :ultra_suspension ... end end
  72. 72. CLOSED for modification OPEN for extension
  73. 73. Replace Conditional With Polymorphism
  74. 74. class MountainBike def price ... end end
  75. 75. module MountainBike def price ... end end
  76. 76. class RigidMountainBike include MountainBike end class FrontSuspensionMountainBike include MountainBike end class FullSuspensionMountainBike include MountainBike end
  77. 77. RigidMountainBike.new(:type => :rigid, ...) FrontSuspensionMountainBike.new(:type => :front_suspension, ...) FullSuspensionMountainBike.new(:type => :full_suspension, ...)
  78. 78. class RigidMountainBike include MountainBike def price (1 + @comission) * @base_price end end
  79. 79. class FrontSuspensionMountainBike include MountainBike def price (1 + @comission) * @base_price + @front_suspension_price end end class FullSuspensionMountainBike include MountainBike def price (1 + @comission) * @base_price + @front_suspension_price + @rear_suspension_price end end
  80. 80. def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_price end if @type_code == :full_suspension (1 + @comission) * @base_price+ @front_suspension_price + @rear_suspension_price end end
  81. 81. def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension raise "should not be called" end if @type_code == :full_suspension raise "should not be called" end end
  82. 82. def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension raise "should not be called" end if @type_code == :full_suspension raise "should not be called" end end
  83. 83. class RigidMountainBike include MountainBike end class FrontSuspensionMountainBike include MountainBike end class FullSuspensionMountainBike include MountainBike end
  84. 84. Coding Dojo http://orlandodojo.org/ http://dojorio.org/
  85. 85. Obrigado! http://www.flickr.com/photos/eurleif/255241547/ http://www.flickr.com/photos/dhammza/91435718/ http://www.flickr.com/photos/krash0387 http://www.flickr.com/photos/benfrantzdale/208672143/ http://www.flickr.com/photos/improveit/1574023621/ http://www.flickr.com/photos/aaroncoyle/972403508 http://www.flickr.com/photos/talios/3726484920 http://www.flickr.com/photos/moow/3412079622 http://www.flickr.com/photos/highwayoflife/2699887178/ @caike http://caikesouza.com http://smallactsmanifesto.org

×