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

Ruby Além dos Trilhos

Ruby Além dos Trilhos

O Rails ao longo dos últimos anos se tornou uma plataforma bastante sólida e respeitada. E boa parte desse sucesso é atribuido a uma comunidade inovadora, vibrante e bem "opinionada". Como consequência, hoje temos um vasto leque de bibliotecas, padrões de projeto, convenções e boas práticas à nossa mão.

Porém, quando não somos criteriosos, todos esses recursos podem facilmente trazer uma grande dor-de-cabeça: o inferno da manutenção. Complexidade desnecessária, alto acoplamento, indireção, todos esses fatores acabam nos atrapalhando quando estamos evoluindo nosso software. Nesta palestra visitaremos alguns exemplos reais desses problemas e aprenderemos como enxergar além para evitá-los, trazendo de volta a tranquilidade ao nosso dia-a-dia de desenvolvimento.

Por João Britto, para o RS on Rails 2013.

Plataformatec

October 19, 2013
Tweet

More Decks by Plataformatec

Other Decks in Programming

Transcript

  1. A dynamic, open source programming language with a focus on

    simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.
  2. A dynamic, open source programming language with a focus on

    simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.
  3. class Integer # Check whether the integer is evenly divisible

    by the argument. # # 0.multiple_of?(0) #=> true # 6.multiple_of?(5) #=> false # 10.multiple_of?(2) #=> true def multiple_of?(number) number != 0 ? self % number == 0 : zero? end end
  4. class Author < ActiveRecord::Base has_many :authorships has_many :books, :through =>

    :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end @author = Author.first # sem has_many through @author.authorships.collect { |a| a.book } # com has_many through @author.books
  5. class Author < ActiveRecord::Base has_many :authorships has_many :books, :through =>

    :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end @author = Author.first # sem has_many through @author.authorships.collect { |a| a.book } # com has_many through @author.books
  6. class Author < ActiveRecord::Base has_many :authorships has_many :books, :through =>

    :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end @author = Author.first # sem has_many through @author.authorships.collect { |a| a.book } # com has_many through @author.books
  7. class Author < ActiveRecord::Base has_many :authorships has_many :books, :through =>

    :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end @author = Author.first # sem has_many through @author.authorships.collect { |a| a.book } # com has_many through @author.books
  8. class Author < ActiveRecord::Base has_many :authorships has_many :books, :through =>

    :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end @author = Author.first # sem has_many through @author.authorships.collect { |a| a.book } # com has_many through @author.books
  9. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  10. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  11. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  12. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base include ActiveRecordExtensions belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  13. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base include ActiveRecordExtensions belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  14. module ActiveRecordExtensions def self.included(base) base.extend ClassMethods end module ClassMethods def

    self.extended(base) class << base alias_method_chain :belongs_to, :through_option end end def belongs_to_with_through_option(association, options = {}) if options[:through] if self.reflect_on_all_associations.find { |a| a.macro == :belongs_to && a.name == options[:through] } define_method association do |*args| through_assoc = self.send(options[:through], *args) through_assoc && through_assoc.send(options[:source] || association, *args) end else raise ':through option in :belongs_to macro must be another valid :belongs_to association' end else belongs_to_without_through_option association, options end end end end
  15. module ActiveRecordExtensions def self.included(base) base.extend ClassMethods end module ClassMethods def

    self.extended(base) class << base alias_method_chain :belongs_to, :through_option end end def belongs_to_with_through_option(association, options = {}) if options[:through] if self.reflect_on_all_associations.find { |a| a.macro == :belongs_to && a.name == options[:through] } define_method association do |*args| through_assoc = self.send(options[:through], *args) through_assoc && through_assoc.send(options[:source] || association, *args) end else raise ':through option in :belongs_to macro must be another valid :belongs_to association' end else belongs_to_without_through_option association, options end end end end
  16. module ActiveRecordExtensions def self.included(base) base.extend ClassMethods end module ClassMethods def

    self.extended(base) class << base alias_method_chain :belongs_to, :through_option end end def belongs_to_with_through_option(association, options = {}) if options[:through] if self.reflect_on_all_associations.find { |a| a.macro == :belongs_to && a.name == options[:through] } define_method association do |*args| through_assoc = self.send(options[:through], *args) through_assoc && through_assoc.send(options[:source] || association, *args) end else raise ':through option in :belongs_to macro must be another valid :belongs_to association' end else belongs_to_without_through_option association, options end end end end
  17. module ActiveRecordExtensions def self.included(base) base.extend ClassMethods end module ClassMethods def

    self.extended(base) class << base alias_method_chain :belongs_to, :through_option end end def belongs_to_with_through_option(association, options = {}) if options[:through] if self.reflect_on_all_associations.find { |a| a.macro == :belongs_to && a.name == options[:through] } define_method association do |*args| through_assoc = self.send(options[:through], *args) through_assoc && through_assoc.send(options[:source] || association, *args) end else raise ':through option in :belongs_to macro must be another valid :belongs_to association' end else belongs_to_without_through_option association, options end end end end
  18. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base include ActiveRecordExtensions belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  19. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base include ActiveRecordExtensions belongs_to :user belongs_to :avatar, :through => :user end @user = User.first # sem through @profile.user.avatar # com through @profile.avatar
  20. module ActiveRecordExtensions def self.included(base) base.extend ClassMethods end module ClassMethods def

    self.extended(base) class << base alias_method_chain :belongs_to, :through_option end end def belongs_to_with_through_option(association, options = {}) if options[:through] if self.reflect_on_all_associations.find { |a| a.macro == :belongs_to && a.name == options[:through] } define_method association do |*args| through_assoc = self.send(options[:through], *args) through_assoc && through_assoc.send(options[:source] || association, *args) end else raise ':through option in :belongs_to macro must be another valid :belongs_to association' end else belongs_to_without_through_option association, options end end end end
  21. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user delegate :avatar, :to => :user, :allow_nil => true end @user = User.first # sem delegate @profile.user.avatar # com delegate @profile.avatar
  22. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user delegate :avatar, :to => :user, :allow_nil => true end @user = User.first # sem delegate @profile.user.avatar # com delegate @profile.avatar
  23. class User < ActiveRecord::Base belongs_to :avatar end class Profile <

    ActiveRecord::Base belongs_to :user delegate :avatar, :to => :user, :allow_nil => true end @user = User.first # sem delegate @profile.user.avatar # com delegate @profile.avatar
  24. require 'will_paginate' module WillPaginate module ViewHelpers pagination_options[:previous_label] = :prev_label.t(:scope =>

    :mislav_will_paginate) pagination_options[:next_label] = :next_label.t(:scope => :mislav_will_paginate) def page_entries_info(collection, options = {}) entry_name = options[:entry_name] || :record.t(:scope => :mislav_will_paginate) entries_name = options[:entries_name] || :records.t(:scope => :mislav_will_paginate) if collection.total_pages < 2 case collection.size when 0 :no_records.t( :entry_name => entry_name, :scope => [:mislav_will_paginate, :messages] ) when 1 :showing_1.t( :entry_name => entry_name, :scope => [:mislav_will_paginate, :messages] ) else :showing_all.t( :size => collection.size, :entries_name => entries_name, :scope => [:mislav_will_paginate, :messages] ) end else :showing.t( :entries_name => entries_name, :from => collection.offset + 1, :to => collection.offset + collection.length, :total => collection.total_entries, :scope => [:mislav_will_paginate, :messages] ) end end end end
  25. class PeopleController < ActionController::Base def index @people = Person.find( :conditions

    => ["added_at > ? and deleted = ?", Time.now.utc, false], :order => "last_name, first_name") @people = @people.reject { |p| p.address.nil? } end end
  26. class Person < ActiveRecord::Base def self.find_recent people = find( :conditions

    => ["added_at > ? and deleted = ?", Time.now.utc, false], :order => "last_name, first_name") people.reject { |p| p.address.nil? } end # ... end class PeopleController < ActionController::Base def index @people = Person.find_recent end end
  27. class Person < ActiveRecord::Base def self.find_recent people = find( :conditions

    => ["added_at > ? and deleted = ?", Time.now.utc, false], :order => "last_name, first_name") people.reject { |p| p.address.nil? } end # ... end class PeopleController < ActionController::Base def index @people = Person.find_recent end end
  28. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) def balance_in_us_dollar if currency == :us_dollar amount elsif currency == :real amount * conversion_rate(:us_dollar, :real) end end def balance_in_real if currency == :real amount elsif currency == :us_dollar amount * conversion_rate(:real, :us_dollar) end end def conversion_rate(from, to) SomeWebservice.get(from, to) end end
  29. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) def balance_in_us_dollar if currency == :us_dollar amount elsif currency == :real amount * conversion_rate(:us_dollar, :real) end end def balance_in_real if currency == :real amount elsif currency == :us_dollar amount * conversion_rate(:real, :us_dollar) end end def conversion_rate(from, to) SomeWebservice.get(from, to) end end
  30. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) def balance_in_us_dollar if currency == :us_dollar amount elsif currency == :real amount * conversion_rate(:us_dollar, :real) end end def balance_in_real if currency == :real amount elsif currency == :us_dollar amount * conversion_rate(:real, :us_dollar) end end def conversion_rate(from, to) SomeWebservice.get(from, to) end end
  31. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) def balance_in_us_dollar if currency == :us_dollar amount elsif currency == :real amount * conversion_rate(:us_dollar, :real) end end def balance_in_real if currency == :real amount elsif currency == :us_dollar amount * conversion_rate(:real, :us_dollar) end end def conversion_rate(from, to) SomeWebservice.get(from, to) end end
  32. class Money def initialize(amount, currency) @amount, @currency = amount, currency

    end def convert_to_us_dollar if currency == :us_dollar @amount elsif currency == :real @amount * ConversionRate.rate(:real, :us_dollar) end end def convert_to_real if currency == :real @amount elsif @currency == :dollar @amount * ConversionRate.rate(:us_dollar, :real) end end end
  33. class Money def initialize(amount, currency) @amount, @currency = amount, currency

    end def convert_to_us_dollar if currency == :us_dollar @amount elsif currency == :real @amount * ConversionRate.rate(:real, :us_dollar) end end def convert_to_real if currency == :real @amount elsif @currency == :dollar @amount * ConversionRate.rate(:us_dollar, :real) end end end
  34. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) composed_of :balance, :class_name => Money, :mapping => %w(amount currency) end
  35. class Account < ActiveRecord::Base validates_numericality_of :amount validates_inclusion_of :currency, :in =>

    %w(us_dollar real) def balance @balance ||= Money.new(amount, currency) end def balance=(balance) self.amount = balance.amount self.currency = balance.currency end end http://blog.plataformatec.com.br/2012/06/about- the-composed_of-removal/
  36. $ find app/models -name '*.rb' | xargs wc -l |

    sort -r | head -4 7567 total 608 app/models/channel.rb 563 app/models/article.rb 477 app/models/video.rb
  37. <% people = Person.find( :conditions => ["added_at > ? and

    deleted = ?", Time.now.utc, false], :order => "last_name, first_name") %> <% people.reject { |p| p.address.nil? }.each do |person| %> <div id="person-<%= person.new_record? ? "new" : person.id %>"> <span class="name"> <%= person.last_name %>, <%= person.first_name %> </span> <span class="age"> <%= (Date.today - person.birthdate) / 365 %> </span> </div> <% end %>
  38. class Person < ActiveRecord::Base # ... def name "#{last_name}, #{first_name}"

    end def age (Date.today - birthdate) / 365 end def pseudo_id new_record? ? "new" : id end end
  39. <% @people.each do |person| %> <div id="person-<%= person.pseudo_id %>"> <span

    class="name"><%= person.name %></span> <span class="age"><%= person.age %></span> </div> <% end %>
  40. render :partial => template_name, :locals => { :my_object => my_object,

    :options => options[:options].join(" "), :use_jquery => options[:use_jquery], :use_css => options[:use_css], :thumb => options[:thumb], :full => options[:full], :width => options[:width], :height => options[:height], :thumb_width => options[:thumb_width], :thumb_height => options[:thumb_height] }
  41. def comment_form(comment, options = {}) # ... render :partial =>

    '_comment_form', :locals => a_huge_amount_of_locals end
  42. • http://www.guygray.org/2013/08/08/the-explanatory-power-of-monkeys-who-cheat/ • http://wall.alphacoders.com/by_sub_category.php?id=199692 • http://upload.wikimedia.org/wikipedia/commons/4/40/Railroad-Gyula-b.jpg • http://yorkdailypicture.blogspot.com.br/2012/01/full-steam-ahead.html • http://flic.kr/p/LJF71

    • http://www.trainsim.com/vbts/showthread.php?299612-Free-Steam-Locomotive- Drawings • http://theredthread.org/2012/03/08/our-burmese-days/ • http://flic.kr/p/Hjt7G • http://tanfield-railway.blogspot.com.br/2011/09/loco-inspection-prep.html • http://www.ppconstructionsafety.com/newsdesk/2013/04/22/rail-maintenance-firms- err-on-worker-safety/ Créditos das imagens