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

Ruby & Rails Antipatterns

6e224152cb7b73c48eb528456a56ee8c?s=47 mrjaba
January 11, 2012

Ruby & Rails Antipatterns

A collection of Ruby/Rails antipatterns presented at @iprug in January 2012

6e224152cb7b73c48eb528456a56ee8c?s=128

mrjaba

January 11, 2012
Tweet

Transcript

  1. RUBY & RAILS ANTIPATTERNS Tom Crinson - @mrjaba - IPRUG

    10th Jan 2012 Wednesday, 11 January 12
  2. WHAT IS AN ANTIPATTERN? Wednesday, 11 January 12

  3. “In software engineering, an anti-pattern (or antipattern) is a pattern

    that may be commonly used but is ineffective and/or counterproductive in practice” (Wikipedia) God Object Sequential Coupling Object Orgy Wednesday, 11 January 12
  4. RUBY IS NOT EXEMPT Wednesday, 11 January 12

  5. THESE ARE NOT LAWS nor are they definitive, most are

    simply opinion - have your pinches of salt* at the ready *flaming pitchforks must wait until the end Wednesday, 11 January 12
  6. RUBY ANTIPATTERNS Wednesday, 11 January 12

  7. UNLESS WITH ELSE def horrible_unless_else unless i_am_a_robot? go_eat_food else go_bend_things

    end end Wednesday, 11 January 12
  8. UNLESS WITH ELSE def horrible_unless_else unless i_am_a_robot? go_eat_food else go_bend_things

    end end def normal_if_else if i_am_a_robot? go_bend_things else go_eat_food end end Wednesday, 11 January 12
  9. RESCUE NIL def horrible_rescue_nil tweets = find_all_my_tweets rescue nil tweets.detect{|tweet|

    tweet.from ~= /"@dhh"/} if tweets end Wednesday, 11 January 12
  10. RESCUE NIL def handle_exceptions_properly tweets = find_all_my_tweets find_tweets_from_ddh(tweets) rescue Timeout::Error

    => e handle_timeout rescue Exception => e logger.error(e) raise end Wednesday, 11 January 12
  11. CATCHALL EXCEPTIONS def handle_exceptions_properly tweets = find_all_my_tweets find_tweets_from_ddh(tweets) rescue Exception

    => e logger.error(e) raise end def handle_exceptions_properly tweets = find_all_my_tweets find_tweets_from_ddh(tweets) rescue Timeout::Error => e retry rescue Net::HTTPServerError => e wait and retry rescue Exception => e logger.error(e) raise end Wednesday, 11 January 12
  12. IF TRUE ELSE FALSE def horrible_if_else if self.has_cake? && self.eats_it?

    return true else return false end end Wednesday, 11 January 12
  13. IF TRUE ELSE FALSE def i_like_cake self.has_cake? && self.eats_it? end

    Wednesday, 11 January 12
  14. IF TRUE ELSE FALSE irb(main):001:0> has_cake = "yes" => "yes"

    irb(main):002:0> eats_it = "hell yes" => "hell yes" irb(main):003:0> has_cake && eats_it => "hell yes" irb(main):004:0> !!(has_cake && eats_it) => true but i need a boolean! Wednesday, 11 January 12
  15. IF TRUE ELSE FALSE def i_like_cake self.has_cake? && self.eats_it? end

    Wednesday, 11 January 12
  16. OVERRIDING METHOD_MISSING but not respond_to? class Cake def eat puts

    "mm eating cake" end def method_missing(method, *args, &block) if method.to_s =~ /^cake/ puts "mmm cake" else super end end end puts Cake.new.respond_to? :eat # true puts Cake.new.respond_to? :cake # false Wednesday, 11 January 12
  17. OVERRIDING METHOD_MISSING but not respond_to? class Cake def respond_to?(method) return

    true if method =~ /^cake/ super end def method_missing(method, *args, &block) if method.to_s =~ /^cake/ puts "mmm cake" else super end end end puts Cake.new.respond_to? :cake # false Wednesday, 11 January 12
  18. NOT KNOWING YOUR TOOLS Aka: Use your language features def

    find_all_the_cakes(bakery_produce) cakes = [] bakery_produce.each do |potential_cake| cakes << potential_cake if is_cake?(potential_cake) end cakes end def find_a_cake(bakery_produce) bakery_produce.each do |potential_cake| return potential_cake if is_cake?(potential_cake) end end Wednesday, 11 January 12
  19. NOT KNOWING YOUR TOOLS Aka: Use your language features def

    find_all_the_cakes(bakery_produce) bakery_produce.select{|potential_cake| is_cake?(potential_cake)} end array[0] vs array.first def find_a_cake(bakery_produce) bakery_produce.detect{|potential_cake| is_cake?(potential_cake)} end Wednesday, 11 January 12
  20. VIOLATING DEMETER if cake.layers.first.ingredients.include?(:vanilla_essence) self.tummy.state = "rumbling" end Aka: Train

    Wreck code Wednesday, 11 January 12
  21. VIOLATING DEMETER if cake.ingredients_include?(:vanilla_essence) self.hungry! end Aka: Train Wreck code

    • You can play on your own. • You can play with your own toys (but you can’t take them apart). • You can play with toys that were given to you. • And you can play with toys you’ve made yourself. Wednesday, 11 January 12
  22. LONG METHODS def bake_a_cake mixing_bowl = [] mixing_bowl << :eggs

    mixing_bowl << :flour mixing_bowl << :milk 100.times do mixing_bowl.shuffle end mixing_bowl = mixing_bowl.join("") cake_tin = [] cake_tin << :grease_proof_paper cake_tin << :grease cake_tin << mixing_bowl.drop(mixing_bowl.length) oven = Oven.new oven.open oven.temperature = 180.degrees oven.insert cake_tin sleep(90.minutes) ... end Wednesday, 11 January 12
  23. LONG METHODS def bake_a_cake mix_indgredients prepare_cake_tin prepare_oven put_cake_in_oven eat_cake end

    def mix_ingredients @mixing_bowl = MixingBowl.new(:eggs,:flour,:milk) @mixing_bowl.mix end def prepare_cake_tin @cake_tin = CakeTin.new @cake_tin.line! @cake_tin.grease! end Wednesday, 11 January 12
  24. RAILS ANTIPATTERNS Wednesday, 11 January 12

  25. LOGIC IN VIEWS <%= if @cake && @cake.is_a?( VictoriaSponge )

    %> <h4> Mmm Spongey </h4> <% else %> <h4> Hmm Not so Spongey </h4> <% end %> Wednesday, 11 January 12
  26. LOGIC IN VIEWS <%= spongeyness_level %> def spongeyness(cake) if cake

    && cake.spongeyness_level > 4 content_tag(:h4, "Mmm Spongey") else content_tag(:h4, "Hmm not so Spongey") end end cake.html.erb cake_helper.rb Bonus Points: Presenters (e.g. draper) Wednesday, 11 January 12
  27. “HELPER” SIDE EFFECTS def cake_deliciousness(cake) if cake && cake.eat =~

    /omnomnom/ content_tag(:h4, "Mmm Delicious") else content_tag(:h4, "Average") end end def cake_servings(cake) if cake.slices? content_tag(:h4, cake.slices ) else content_tag(:h4, "The cake has been eated!" ) end end <%= cake_deliciousness(@cake) %> => <h4> Mmm Delicious </h4> <%= cake_servings(@cake) %> => <h4> The cake has been eated! </h4> cake.html.erb cake_helper.rb a cake can only be tested by eating it! Wednesday, 11 January 12
  28. COMPLEX CONTROLLERS class SearchController < ApplicationController def search if params[:advanced]

    context = params[:advanced][:context] search_term = params[:advanced][:term] results = AdvancedSearchService.search(context, search_term) @normalized_results = normalize_results(results) respond_with(@normalized_results) else search_term = params[:simple][:term] @results = SimpleSearchService.search(search_term) respond_with(@results) end end end Wednesday, 11 January 12
  29. COMPLEX CONTROLLERS class SimpleSearchController < ApplicationController def create @search =

    Search.new(params) respond_with @search end end Keep it simple Break out complex logic into models One controller per resource Wednesday, 11 January 12
  30. FAAAT MODELS class Cake < ActiveRecord::Base #Eating Methods def eat_with_fork(person)

    person.munch(self) until self.empty? end #Distribution methods def slices(degrees_per_slice) 360/degrees_per_slice end #Representation Methods def to_xml ... end def to_html ... end def as_json ... end end Wednesday, 11 January 12
  31. FAAAT MODELS class CakePresenter def initialize(cake) @cake = cake end

    def to_xml ... end def to_html ... end def as_json ... end end def CakeSlicer def initialize(cake) @cake = cake end def slices(degrees_per_slice) 360/degrees_per_slice end end Wednesday, 11 January 12
  32. MANY MANY MORE Referring to ActiveRecord classes in migrations [1]

    Data Migrations [2] Fixtures - especial with associations [3] Script like Rake task [4] No Database indexes [5] Wednesday, 11 January 12
  33. CAKE! THANK YOU! Wednesday, 11 January 12

  34. RESOURCES Inspired by: ruby rogues: http://rubyrogues.com/ (episode 32) dan manges:

    http://www.dan-manges.com/blog/28 Further Reading: [1,2] http://complicated-simplicity.com/2010/05/using-models-in-rails-migrations/ [3] http://jakescruggs.blogspot.com/2007/06/why-i-hate-using-rails-fixtures-in.html [4] http://blog.jayfields.com/2006/11/ruby-testing-rake-tasks.html [5] http://rails-bestpractices.com/posts/21-always-add-db-index Image: www.flickr.com/photos/fairtradefairy/3708326594/ Wednesday, 11 January 12