Slides

Os piores códigos Ruby já vistos - TDC Florianópolis 2016

Description
Slides da palestra "Os piores códigos Ruby já vistos" apresentada na TDC Florianópolis 2016, na trilha Ruby, em 14/05/2016. http://www.thedevelopersconference.com.br/tdc/2016/florianopolis/trilha-ruby Muitas aplicações escritas em Ruby são ótimas, mas também existe códigos do mal aplicando técnicas de POG. Muitas gambiarras podem ser usadas em várias linguagens, mas em Ruby, quando acontece, a proporção é maior. É muito fácil escrever código Ruby com efeitos colaterais. Vocês verão uma coleção de códigos ruins em Ruby, com a descrição de como eles afetaram negativamente seus sistemas e as soluções para consertá-los e evitá-los. Classes longas, acoplamento, má aplicação de OO, código ilegível, fluxo emaranhados, nomes equivocados e outras coisas que vocês nem imaginam são exemplos do que vocês terão.
Categories
Published
of 161
All materials on our website are shared by users. If you have any questions about copyright issues, please report us to resolve them. We are always happy to assist you.
Related Documents
Share
Transcript
  • 1. @Prodis Os piores códigos Ruby já vistos TDC Florianópolis 2016 @Prodis
  • 2. @Prodis Fernando Hamasaki de Amorim • Desenvolvedor Ruby desde 2009 • Trabalho na Locaweb, a maior empresa de hospedagem do Brasil • Desenvolvo aplicações web desde 2000 • .NET, Java, JavaScript, PHP, ASP.
  • 3. @Prodis Fernando Hamasaki de Amorim
  • 4. @Prodis Fernando Hamasaki de Amorim
  • 5. @Prodis WOP
  • 6. @Prodis WOP Workaround Oriented Programming
  • 7. @Prodis POG Programação Orientada a Gambiarras
  • 8. @Prodis POG POG é uma técnica avançada de desenvolvimento de software que tem como base a utilização de todo tipo de gambiarra, remendo e tudo de pior que um código pode ter. POG se baseia em conceitos como duplicação de código, fluxos redundantes, tarefas desnecessárias
 e reinvenção de rodas.
  • 9. @Prodis "The names have been changed to protect the innocent." Os piores códigos Ruby já vistos
  • 10. @Prodis Um primeiro exemplo de POG:
 mascarando números de cartão de crédito
  • 11. @Prodis describe '#mask_credit_card' do let(:number) { '5464193830403276' } it 'returns masked credit card number' do masked = mask_credit_card(number) expect(masked).to eq '************3276' end end
  • 12. @Prodis def mask_credit_card(number) limit = number.length - 4 “#{'*' * limit}#{number[limit..-1]}” end
  • 13. @Prodis def mask_credit_card_pog(number) (number.length - 4).times do |i| number[i] = '*' end number end
  • 14. @Prodis describe '#mask_credit_card_pog' do let(:number) { '5464193830403276' } it 'returns masked credit card number' do masked = mask_credit_card_pog(number) expect(masked).to eq '************3276' end it 'does not change number variable' do mask_credit_card_pog(number) expect(number).to eq '5464193830403276' end end
  • 15. @Prodis #mask_credit_card_pog returns masked credit card number does not change number variable (FAILED - 1) Failures: 1) #mask_credit_card_pog does not change number variable Failure/Error: expect(number).to eq '5464193830403276' expected: "5464193830403276" got: "************3276" (compared using ==) # ./spec/mask_credit_card/mask_credit_card_spec.rb: 23:in `block (2 levels) in <top (required)>' Finished in 0.0202 seconds (files took 0.17324 seconds to load) 2 examples, 1 failure
  • 16. @Prodis def mask_credit_card_pog(number) (number.length - 4).times do |i| number[i] = '*' end number end
  • 17. @Prodis Fluxos obscuros
  • 18. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 19. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 20. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 21. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 22. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 23. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 24. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) if site.blank? flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return else domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true if domain.save flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path return else flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end end end end
  • 25. @Prodis Como corrigir isso?
  • 26. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) unless site flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return end domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true unless domain.save flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path end end
  • 27. @Prodis class Support::DomainsController < Support::BaseController def create site = Site.find_by(name: params[:domain][:site]) unless site flash[:alert] = I18n.t('support.domains.errors.without_site') redirect_to new_support_domain_path return end domain = site.domains.build(address: params[:domain][:address]) domain.support_create = true unless domain.save flash[:alert] = I18n.t('support.domains.errors.invalid') redirect_to new_support_domain_path return end flash[:success] = I18n.t('support.domains.success') redirect_to support_domains_path end end
  • 28. @Prodis No Ruby way
  • 29. @Prodis class PaymentGatewayWOP def initialize(options = {}) raise ArgumentError if options[:email].to_s.strip.empty? raise ArgumentError if options[:token].to_s.strip.empty? @options = options end def email @options[:email] end def token @options[:token] end def identification @options[:identification] end def billing_type @options[:billing_type] end def billing_status @options[:billing_status] end def message @options[:message] end def exists? @options[:message] =~ /Account found/ end def is_active? @options[:billing_status] == 'active' end def is_seller? @options[:billing_type] == 'seller' || @options[:billing_type] == 'company' end # other methods omitted end
  • 30. @Prodis class PaymentGatewayWOP def initialize(options = {}) raise ArgumentError if options[:email].to_s.strip.empty? raise ArgumentError if options[:token].to_s.strip.empty? @options = options end def email @options[:email] end def token @options[:token] end def identification @options[:identification] end def billing_type @options[:billing_type] end # other methods omitted end
  • 31. @Prodis class PaymentGatewayWOP def initialize(options = {}) raise ArgumentError if options[:email].to_s.strip.empty? raise ArgumentError if options[:token].to_s.strip.empty? @options = options end def email @options[:email] end def token @options[:token] end def identification @options[:identification] end def billing_type @options[:billing_type] end # other methods omitted end
  • 32. @Prodis class PaymentGateway attr_reader :email, :token def initialize(options = {}) @email = options.fetch(:email) @token = options.fetch(:token) @options = options end def identification options[:identification] end def billing_type options[:billing_type] end # other public methods omitted private attr_reader :options # other methods omitted end
  • 33. @Prodis class PaymentGateway attr_reader :email, :token def initialize(options = {}) @email = options.fetch(:email) @token = options.fetch(:token) @options = options end def identification options[:identification] end def billing_type options[:billing_type] end # other public methods omitted private attr_reader :options # other methods omitted end
  • 34. @Prodis class PaymentGateway attr_reader :email, :token def initialize(options = {}) @email = options.fetch(:email) @token = options.fetch(:token) @options = options end [:identification, :billing_type, :billing_status, :message].each do |method| define_method(method) do options[method] end end # other public methods omitted private attr_reader :options # other methods omitted end
  • 35. @Prodis class PaymentGateway attr_reader :email, :token # constructor omitted [:identification, :billing_type, :billing_status, :message].each do |method| define_method(method) do options[method] end end def exists? message =~ /Account found/ end def is_active? billing_status == 'active' end def is_seller? billing_type == 'seller' || billing_type == 'company' end private attr_reader :options # other methods omitted end
  • 36. @Prodis class PaymentGateway attr_reader :email, :token # other methods omitted def exists? message =~ /Account found/ end def active? billing_status == 'active' end def seller? billing_type == 'seller' || billing_type == 'company' end private attr_reader :options # other methods omitted end
  • 37. @Prodis class PaymentGatewayWOP def initialize(options = {}) raise ArgumentError if options[:email].to_s.strip.empty? raise ArgumentError if options[:token].to_s.strip.empty? @options = options end def email @options[:email] end def token @options[:token] end def identification @options[:identification] end def billing_type @options[:billing_type] end def billing_status @options[:billing_status] end def message @options[:message] end def exists? @options[:message] =~ /Account found/ end def is_active? @options[:billing_status] == 'active' end def is_seller? @options[:billing_type] == 'seller' || @options[:billing_type] == 'company' end # other methods omitted end
  • 38. @Prodis class PaymentGateway attr_reader :email, :token def initialize(options = {}) @email = options.fetch(:email) @token = options.fetch(:token) @options = options end [:identification, :billing_type, :billing_status, :message].each do |method| define_method(method) do options[method] end end def exists? message =~ /Account found/ end def active? billing_status == 'active' end def seller? billing_type == 'seller' || billing_type == 'company' end private attr_reader :options # other methods end
  • 39. @Prodis Problemas de nomenclatura
  • 40. @Prodis class ImageWidgetImporter < WidgetImporter def import(img_element, row_number, position) return if img_element.blank? || img_element['src'].blank? create_image_widget(img_element, row_number, position) end def import! @page.widgets.where(kind: 'text').each do |widget| content = Nokogiri::HTML(widget.content, nil, 'UTF-8') next unless has_internal_image?(content) images = content.css('img').select do |image| internal_image?(image) end images.each { |image| download_and_change_image_src(image) } widget.update_attribute(:content, content.inner_html) end end private def kind 'image' end def create_image_widget(img_element, row_number, position) widget = create(row_number: row_number, position: position, remote_image_url: img_element['src']) source = (AppConfig.assets_host + widget.image.url) widget.content = @template_adapter.render_widget_content('image', alt: '', src: source) widget.save! widget end # Create widget_image to Text Widget def create_widget_image(url) widget_image = WidgetImage.new remote_image_url: url widget_image.site_id = @page.site.id widget_image.save! widget_image end # other methods omitted end
  • 41. @Prodis class ImageWidgetImporter < WidgetImporter def import(img_element, row_number, position) return if img_element.blank? || img_element['src'].blank? create_image_widget(img_element, row_number, position) end def import! @page.widgets.where(kind: 'text').each do |widget| content = Nokogiri::HTML(widget.content, nil, 'UTF-8') next unless has_internal_image?(content) images = content.css('img').select do |image| internal_image?(image) end images.each { |image| download_and_change_image_src(image) } widget.update_attribute(:content, content.inner_html) end end private def kind 'image' end # other methods omitted end
  • 42. @Prodis class ImageWidgetImporter < WidgetImporter def import(img_element, row_number, position) return if img_element.blank? || img_element['src'].blank? create_image_widget(img_element, row_number, position) end def import! @page.widgets.where(kind: 'text').each do |widget| content = Nokogiri::HTML(widget.content, nil, 'UTF-8') next unless has_internal_image?(content) images = content.css('img').select do |image| internal_image?(image) end images.each { |image| download_and_change_image_src(image) } widget.update_attribute(:content, content.inner_html) end end private def kind 'image' end # other methods omitted end
  • 43. @Prodis class ImageWidgetImporter < WidgetImporter def import(img_element, row_number, position) return if img_element.blank? || img_element['src'].blank? create_image_widget(img_element, row_number, position) end def import_from_text_widget @page.widgets.where(kind: 'text').each do |widget| content = Nokogiri::HTML(widget.content, nil, 'UTF-8') next unless has_internal_image?(content) images = content.css('img').select do |image| internal_image?(image) end images.each { |image| download_and_change_image_src(image) } widget.update_attribute(:content, content.inner_html) end end private def kind 'image' end # other methods omitted end
  • 44. @Prodis class ImageWidgetImporter < WidgetImporter # other public methods omitted private def create_image_widget(img_element, row_number, position) widget = create(row_number: row_number, position: position, remote_image_url: img_element['src']) source = (AppConfig.assets_host + widget.image.url) widget.content = @template_adapter.render_widget_content('image', alt: '', src: source) widget.save! widget end # Create image widget to text widget def create_widget_image(url) widget_image = WidgetImage.new remote_image_url: url widget_image.site_id = @page.site.id widget_image.save! widget_image end # other methods omitted end
  • 45. @Prodis class ImageWidgetImporter < WidgetImporter # other public methods omitted private def create_image_widget(img_element, row_number, position) widget = create(row_number: row_number, position: position, remote_image_url: img_element['src']) source = (AppConfig.assets_host + widget.image.url) widget.content = @template_adapter.render_widget_content('image', alt: '', src: source) widget.save! widget end # Create image widget to text widget def create_widget_image(url) widget_image = WidgetImage.new remote_image_url: url widget_image.site_id = @page.site.id widget_image.save! widget_image end # other methods omitted end
  • 46. @Prodis class ImageWidgetImporter < WidgetImporter # other public methods omitted private def create_image_widget(img_element, row_number, position) widget = create(row_number: row_number, position: position, remote_image_url: img_element['src']) source = (AppConfig.assets_host + widget.image.url) widget.content = @template_adapter.render_widget_content('image', alt: '', src: source) widget.save! widget end def create_image_widget_to_text_widget(url) widget_image = WidgetImage.new remote_image_url: url widget_image.site_id = @page.site.id widget_image.save! widget_image end # other methods omitted end
  • 47. @Prodis Orientação a Objetos
  • 48. @Prodis Orientação a Objetos Herança com propósito de reuso de código
  • 49. @Prodis class Installation::FromFeed < Installation::FromBase def install(args) # implementation omitted end end class Installation::FromHosting < Installation::FromBase def install(args) # implementation omitted end end class Installation::FromMigration < Installation::FromBase def install(args) # implementation omitted end end
  • 50. @Prodis class Installation::FromFeed < Installation::FromBase def install(args) # implementation omitted end end class Installation::FromHosting < Installation::FromBase def install(args) # implementation omitted end end class Installation::FromMigration < Installation::FromBase def install(args) # implementation omitted end end
  • 51. @Prodis class Installation::FromBase include Rails::LabeledLog::Logging attr_writer :customers_api, :installer, :mailer def install(args) raise NotImplementedError end def customers_api @customers_api ||= CustomersApi.new end def installer @installer ||= Installation::Installer.new end def mailer @mailer ||= Installation::Mailer.new end end
  • 52. @Prodis class Installation::FromBase include Rails::LabeledLog::Logging attr_writer :customers_api, :installer, :mailer def install(args) raise NotImplementedError end def customers_api @customers_api ||= CustomersApi.new end def installer @installer ||= Installation::Installer.new end def mailer @mailer ||= Installation::Mailer.new end end
  • Foto Clipe Final

    Jul 12, 2018

    Coding Dojo Cesupa

    Jul 12, 2018
    We Need Your Support
    Thank you for visiting our website and your interest in our free products and services. We are nonprofit website to share and download documents. To the running of this website, we need your help to support us.

    Thanks to everyone for your continued support.

    No, Thanks