Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

466 views

Published on

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.

Published in: Technology
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

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

  1. 1. @Prodis Os piores códigos Ruby já vistos TDC Florianópolis 2016 @Prodis
  2. 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. 3. @Prodis Fernando Hamasaki de Amorim
  4. 4. @Prodis Fernando Hamasaki de Amorim
  5. 5. @Prodis WOP
  6. 6. @Prodis WOP Workaround Oriented Programming
  7. 7. @Prodis POG Programação Orientada a Gambiarras
  8. 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. 9. @Prodis "The names have been changed to protect the innocent." Os piores códigos Ruby já vistos
  10. 10. @Prodis Um primeiro exemplo de POG:
 mascarando números de cartão de crédito
  11. 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. 12. @Prodis def mask_credit_card(number) limit = number.length - 4 “#{'*' * limit}#{number[limit..-1]}” end
  13. 13. @Prodis def mask_credit_card_pog(number) (number.length - 4).times do |i| number[i] = '*' end number end
  14. 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. 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. 16. @Prodis def mask_credit_card_pog(number) (number.length - 4).times do |i| number[i] = '*' end number end
  17. 17. @Prodis Fluxos obscuros
  18. 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. 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. 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. 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. 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. 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. 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. 25. @Prodis Como corrigir isso?
  26. 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. 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. 28. @Prodis No Ruby way
  29. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 39. @Prodis Problemas de nomenclatura
  40. 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. 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. 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. 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. 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. 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. 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. 47. @Prodis Orientação a Objetos
  48. 48. @Prodis Orientação a Objetos Herança com propósito de reuso de código
  49. 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. 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. 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. 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
  53. 53. @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
  54. 54. @Prodis Como corrigir isso?
  55. 55. @Prodis module Installation::Infra include Rails::LabeledLog::Logging attr_writer :customers_api, :installer, :mailer def customers_api @customers_api ||= CustomersApi.new end def installer @installer ||= Provisioner::Installation::Installer.new end def mailer @mailer ||= Provisioner::Installation::Mailer.new end end
  56. 56. @Prodis module Installation::Infra include Rails::LabeledLog::Logging attr_writer :customers_api, :installer, :mailer def customers_api @customers_api ||= CustomersApi.new end def installer @installer ||= Provisioner::Installation::Installer.new end def mailer @mailer ||= Provisioner::Installation::Mailer.new end end
  57. 57. @Prodis class Installation::FromFeed include Installation::Infra def install(args) # implementation omitted end end class Installation::FromHosting include Installation::Infra def install(args) # implementation omitted end end class Installation::FromMigration include Installation::Infra def install(args) # implementation omitted end end
  58. 58. @Prodis Orientação a Objetos Equívoco de herança
  59. 59. @Prodis DNS Uma rápida introdução
  60. 60. @Prodis
  61. 61. @Prodis class WsDns attr_reader :host, :user, :timeout def initialize(args) @host = args[:host] @user = args[:user] @timeout = args.fetch(:timeout, 5) end def create_entry(options) # implementation omitted end def delete_entry(options) # implementation omitted end def get_entry(options) # implementation omitted end def has_entry?(options) # implementation omitted end # other methods to DNS zone end
  62. 62. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  63. 63. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  64. 64. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  65. 65. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  66. 66. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  67. 67. @Prodis class AWsDns < CnameWsDns protected def type 'A' end end
  68. 68. @Prodis class AWsDns < CnameWsDns protected def type 'A' end end
  69. 69. @Prodis class CnameWsDns attr_reader :ws_dns, :zone, :content def initialize(options) @ws_dns = WsDns.new(options) @zone = options[:zone] @content = options.fetch(:content, zone) end def create_entry(subdomain) ws_dns.create_entry(type: type, content: content, name: subdomain, zone: zone) end def delete_entry(subdomain) ws_dns.delete_entry(type: type, content: content, name: subdomain, zone: zone) end def has_entry?(subdomain) ws_dns.has_entry?(type: type, name: subdomain, zone: zone) end protected def type 'CNAME' end end
  70. 70. @Prodis class TxtWsDns < CnameWsDns protected def type 'TXT' end end
  71. 71. @Prodis class TxtWsDns < CnameWsDns protected def type 'TXT' end end
  72. 72. @Prodis
  73. 73. @Prodis Como corrigir isso?
  74. 74. @Prodis
  75. 75. @Prodis Orientação a Objetos Classe base conhecendo seus filhos
  76. 76. @Prodis class TransactionResponseParser attr_reader :xml def initialize(xml) @xml = xml end def parse # omitted implementation end private # specific transaction methods omitted end
  77. 77. @Prodis class ResponseParser attr_reader :xml def initialize(xml) @xml = xml end def parse # omitted implementation end # omitted protected methods end
  78. 78. @Prodis class TransactionResponseParser < ResponseParser private # specific transaction methods omitted end class AccountResponseParser < ResponseParser private # specific account methods omitted end
  79. 79. @Prodis class ResponseParser def self.transaction?(xml) xml.include?('<transaction>') end def self.get_parser(xml) ResponseParser.transaction?(xml) ? TransactionResponseParser.new(xml) : AccountResponseParser.new(xml) end def initialize(xml) @xml = xml end def parse # omitted implementation end end
  80. 80. @Prodis Como corrigir isso?
  81. 81. @Prodis module ResponseParserFactory def self.build(xml) if xml.include?('<transaction>') TransactionResponseParser.new(xml) else AccountResponseParser.new(xml) end end end
  82. 82. @Prodis A pior classe
  83. 83. @Prodis class DomainChecker extend Memoist DOMAIN_REGEXP = /^[a-z0-9]+(-[a-z0-9]+)*(.[a-z0-9]+(-[a-z0-9]+)*)+$/ attr_accessor :domain def initialize(args = {}) @domain = args[:domain] end def check_new check_existing end def status if dns_adapter.ns_locaweb? a_entry_locaweb = dns_adapter.a_entry_locaweb if a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites return :ok elsif a_entry_locaweb == false return :unavailable else return :already_using end end if domain_checker_result["error"] == "generic" return :generic_error end if domain_checker_result["error"] == "unsupported_tld" return :unsupported_tld end if domain_checker_result["available"] return :register end if dns_adapter.a_value == AppConfig.ip_lvs_criador_de_sites return :ok else return :config_dns end end memoize :status def available_domain_by_user(user) if domain.blank? return {valid: false, notice: :invalid, message: :blank} end if !domain.match(DOMAIN_REGEXP) return {valid: false, notice: :invalid, message: :invalid} end if forbidden_domain? return {valid: false, notice: :invalid, message: :forbidden_domain} end if Domain.where(address: domain).count > 0 current_domain = Domain.where(address: domain).first if (current_domain.site.account.users.include?(user) rescue false) return {valid: false, notice: :invalid, message: :already_using} else return {valid: false, notice: :invalid, message: :already_exists} end end if !domain_checker_result["valid"] && domain_checker_result["error"] != "unsupported_tld" return {valid: false, notice: :invalid, message: :invalid} end if domain_checker_result["error"] == "unsupported_tld" return {valid: true, notice: :unsupported_tld} end if domain_checker_result["available"] return {valid: true, notice: :register} end if domain_checker_result["customer_login"].blank? return {valid: true, notice: :config_dns} end if domain_checker_result["customer_login"].downcase == user.username.downcase Rails.logger.info "user owner domain" if dns_adapter.a_entry_locaweb? if dns_adapter.a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites_old return {valid: true, notice: :old_csit} else return {valid: true, notice: :already_using} end else Rails.logger.info "Without entry A" return {valid: true, notice: :owner_domain} end else Rails.logger.info "user does not owner domain" return {valid: false, notice: :not_owner} end end def details { entry_a: dns_adapter.a_value, entry_ns: dns_adapter.ns_value, entry_cname: dns_adapter.cname_value }.merge(domain_checker_result) end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def dns_adapter DnsAdapter.new(domain: CGI.escape(domain)) end memoize :dns_adapter def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result def get_token WsAuthentication.new(AppConfig.wsauthentication.url).authenticate(AppConfig.wsauthentication.user, AppConfig.wsauthent end memoize :get_token def external_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/external_check" begin JSON(http_get(url)) rescue RestClient::NotImplemented return { "valid" => false, "available" => false, "error" => 'unsupported_tld' } rescue RestClient::InternalServerError => exception Rails.logger.error "[ERROR] GET #{url}: #{exception.message}n" "Response: #{exception.http_body}" return { "valid" => false, "available" => false, "error" => 'generic' } rescue => exception Rails.logger.error exception.print raise exception end end memoize :external_check def internal_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/internal_check" JSON(http_get(url)) end memoize :internal_check def forbidden_domain? uri = "#{AppConfig.registro_domain_url}/domain/#{domain}/check" begin response = JSON(CasSaas::CasRestClient.new.get(uri)) !response["valid"] rescue => e Rails.logger.info e.message true end end memoize :forbidden_domain? def http_get(url, headers = {}) Rails.logger.info "chamando GET #{url}, headers: #{headers}" response = RestClient.get url, headers Rails.logger.info "response #{response}" response end end
  84. 84. @Prodis Cenário de negócio da classe DomainChecker
  85. 85. @Prodis Verificação de domínio
  86. 86. @Prodis class DomainChecker # ... def check_new # omitted implementation end def status # omitted implementation end memoize :status def available_domain_by_user(user) # omitted implementation end def details # omitted implementation end def check_existing # omitted implementation end # ... end
  87. 87. @Prodis class DomainChecker extend Memoist attr_accessor :domain def initialize(args = {}) @domain = args[:domain] end # ... end
  88. 88. @Prodis class DomainChecker extend Memoist # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end # ... end
  89. 89. @Prodis class DomainChecker extend Memoist attr_accessor :domain def initialize(args = {}) @domain = args[:domain] end # ... end
  90. 90. @Prodis def status if dns_adapter.ns_locaweb? a_entry_locaweb = dns_adapter.a_entry_locaweb if a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites return :ok elsif a_entry_locaweb == false return :unavailable else return :already_using end end if domain_checker_result["error"] == "generic" return :generic_error end if domain_checker_result["error"] == "unsupported_tld" return :unsupported_tld end if domain_checker_result["available"] return :register end if dns_adapter.a_value == AppConfig.ip_lvs_criador_de_sites return :ok else return :config_dns end end memoize :status
  91. 91. @Prodis def dns_adapter DnsAdapter.new(domain: CGI.escape(domain)) end memoize :dns_adapter def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result
  92. 92. @Prodis def get_token WsAuthentication.new(AppConfig.wsauthentication.url).authenticate(AppConfig. wsauthentication.user, AppConfig.wsauthentication.pass) end memoize :get_token def external_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/ external_check" begin JSON(http_get(url)) rescue RestClient::NotImplemented return { "valid" => false, "available" => false, "error" => 'unsupported_tld' } rescue RestClient::InternalServerError => exception Rails.logger.error "[ERROR] GET #{url}: #{exception.message}n" "Response: #{exception.http_body}" return { "valid" => false, "available" => false, "error" => 'generic' } rescue => exception Rails.logger.error exception.print raise exception end end memoize :external_check
  93. 93. @Prodis def internal_check url = "#{AppConfig.registro_service_url}/domain_availability/ #{domain}/internal_check" JSON(http_get(url)) end memoize :internal_check def forbidden_domain? uri = "#{AppConfig.registro_domain_url}/domain/#{domain}/check" begin response = JSON(CasSaas::CasRestClient.new.get(uri)) !response["valid"] rescue => e Rails.logger.info e.message true end end memoize :forbidden_domain?
  94. 94. @Prodis class DomainChecker extend Memoist attr_accessor :domain def initialize(args = {}) @domain = args[:domain] end # ... end
  95. 95. @Prodis def status if dns_adapter.ns_locaweb? a_entry_locaweb = dns_adapter.a_entry_locaweb if a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites return :ok elsif a_entry_locaweb == false return :unavailable else return :already_using end end if domain_checker_result["error"] == "generic" return :generic_error end if domain_checker_result["error"] == "unsupported_tld" return :unsupported_tld end if domain_checker_result["available"] return :register end if dns_adapter.a_value == AppConfig.ip_lvs_criador_de_sites return :ok else return :config_dns end end memoize :status
  96. 96. @Prodis def available_domain_by_user(user) if domain.blank? return {valid: false, notice: :invalid, message: :blank} end if !domain.match(DOMAIN_REGEXP) return {valid: false, notice: :invalid, message: :invalid} end if forbidden_domain? return {valid: false, notice: :invalid, message: :forbidden_domain} end if Domain.where(address: domain).count > 0 current_domain = Domain.where(address: domain).first if (current_domain.site.account.users.include?(user) rescue false) return {valid: false, notice: :invalid, message: :already_using} else return {valid: false, notice: :invalid, message: :already_exists} end end if !domain_checker_result["valid"] && domain_checker_result["error"] != "unsupported_tld" return {valid: false, notice: :invalid, message: :invalid} end if domain_checker_result["error"] == "unsupported_tld" return {valid: true, notice: :unsupported_tld} end if domain_checker_result["available"] return {valid: true, notice: :register} end if domain_checker_result["customer_login"].blank? return {valid: true, notice: :config_dns} end if domain_checker_result["customer_login"].downcase == user.username.downcase Rails.logger.info "user owner domain" if dns_adapter.a_entry_locaweb? if dns_adapter.a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites_old return {valid: true, notice: :old_csit} else return {valid: true, notice: :already_using} end else Rails.logger.info "Without entry A" return {valid: true, notice: :owner_domain} end else Rails.logger.info "user does not owner domain" return {valid: false, notice: :not_owner} end end
  97. 97. @Prodis def available_domain_by_user(user) if domain.blank? return {valid: false, notice: :invalid, message: :blank} end if !domain.match(DOMAIN_REGEXP) return {valid: false, notice: :invalid, message: :invalid} end if forbidden_domain? return {valid: false, notice: :invalid, message: :forbidden_domain} end if Domain.where(address: domain).count > 0 current_domain = Domain.where(address: domain).first if (current_domain.site.account.users.include?(user) rescue false) return {valid: false, notice: :invalid, message: :already_using} else return {valid: false, notice: :invalid, message: :already_exists} end end # ... end
  98. 98. @Prodis def available_domain_by_user(user) if domain.blank? return {valid: false, notice: :invalid, message: :blank} end if !domain.match(DOMAIN_REGEXP) return {valid: false, notice: :invalid, message: :invalid} end if forbidden_domain? return {valid: false, notice: :invalid, message: :forbidden_domain} end if Domain.where(address: domain).count > 0 current_domain = Domain.where(address: domain).first if (current_domain.site.account.users.include?(user) rescue false) return {valid: false, notice: :invalid, message: :already_using} else return {valid: false, notice: :invalid, message: :already_exists} end end # ... end
  99. 99. @Prodis def available_domain_by_user(user) if domain.blank? return {valid: false, notice: :invalid, message: :blank} end if !domain.match(DOMAIN_REGEXP) return {valid: false, notice: :invalid, message: :invalid} end if forbidden_domain? return {valid: false, notice: :invalid, message: :forbidden_domain} end if Domain.where(address: domain).count > 0 current_domain = Domain.where(address: domain).first if (current_domain.site.account.users.include?(user) rescue false) return {valid: false, notice: :invalid, message: :already_using} else return {valid: false, notice: :invalid, message: :already_exists} end end # ... end
  100. 100. @Prodis def available_domain_by_user(user) # … if domain_checker_result["customer_login"].downcase == user.username.downcase Rails.logger.info "user owner domain" if dns_adapter.a_entry_locaweb? if dns_adapter.a_entry_locaweb == AppConfig.ip_lvs_criador_de_sites_old return {valid: true, notice: :old_csit} else return {valid: true, notice: :already_using} end else Rails.logger.info "Without entry A" return {valid: true, notice: :owner_domain} end else Rails.logger.info "user does not owner domain" return {valid: false, notice: :not_owner} end end
  101. 101. @Prodis def available_domain_by_user(user) # … if !domain_checker_result["valid"] && domain_checker_result["error"] != "unsupported_tld" return {valid: false, notice: :invalid, message: :invalid} end if domain_checker_result["error"] == "unsupported_tld" return {valid: true, notice: :unsupported_tld} end if domain_checker_result["available"] return {valid: true, notice: :register} end if domain_checker_result["customer_login"].blank? return {valid: true, notice: :config_dns} end # … end
  102. 102. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  103. 103. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  104. 104. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  105. 105. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  106. 106. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  107. 107. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  108. 108. @Prodis def external_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/external_check" begin JSON(http_get(url)) rescue RestClient::NotImplemented return { "valid" => false, "available" => false, "error" => 'unsupported_tld' } rescue RestClient::InternalServerError => exception Rails.logger.error "[ERROR] GET #{url}: #{exception.message}n" "Response: #{exception.http_body}" return { "valid" => false, "available" => false, "error" => 'generic' } rescue => exception Rails.logger.error exception.print raise exception end end memoize :external_check def internal_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/internal_check" JSON(http_get(url)) end memoize :internal_check
  109. 109. @Prodis def external_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/external_check" begin JSON(http_get(url)) rescue RestClient::NotImplemented return { "valid" => false, "available" => false, "error" => 'unsupported_tld' } rescue RestClient::InternalServerError => exception Rails.logger.error "[ERROR] GET #{url}: #{exception.message}n" "Response: #{exception.http_body}" return { "valid" => false, "available" => false, "error" => 'generic' } rescue => exception Rails.logger.error exception.print raise exception end end memoize :external_check def internal_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/internal_check" JSON(http_get(url)) end memoize :internal_check
  110. 110. @Prodis class DomainChecker # ... def http_get(url, headers = {}) Rails.logger.info "chamando GET #{url}, headers: #{headers}" response = RestClient.get url, headers Rails.logger.info "response #{response}" response end end
  111. 111. @Prodis def external_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/external_check" begin JSON(http_get(url)) rescue RestClient::NotImplemented return { "valid" => false, "available" => false, "error" => 'unsupported_tld' } rescue RestClient::InternalServerError => exception Rails.logger.error "[ERROR] GET #{url}: #{exception.message}n" "Response: #{exception.http_body}" return { "valid" => false, "available" => false, "error" => 'generic' } rescue => exception Rails.logger.error exception.print raise exception end end memoize :external_check def internal_check url = "#{AppConfig.registro_service_url}/domain_availability/#{domain}/internal_check" JSON(http_get(url)) end memoize :internal_check
  112. 112. @Prodis class DomainChecker # ... def check_new check_existing end def check_existing return external_check if external_check["error"] == "generic" return external_check if external_check["error"] == "invalid_domain" return external_check if external_check["error"] == "unsupported_tld" return external_check if external_check["available"] return external_check if internal_check["available"] internal_check end private def domain_checker_result domain_checker = DomainChecker.new(domain: CGI.escape(domain)) domain_checker_result = domain_checker.check_new end memoize :domain_checker_result # ... end
  113. 113. @Prodis class DomainChecker # ... def details { entry_a: dns_adapter.a_value, entry_ns: dns_adapter.ns_value, entry_cname: dns_adapter.cname_value }.merge(domain_checker_result) end private def dns_adapter DnsAdapter.new(domain: CGI.escape(domain)) end memoize :dns_adapter #... end
  114. 114. @Prodis class DomainChecker # ... private def get_token WsAuthentication.new(AppConfig.wsauthentication.url) .authenticate(AppConfig.wsauthentication.user, AppConfig.wsauthentication.pass) end memoize :get_token end
  115. 115. @Prodis Problemas da classe DomainChecker
  116. 116. @Prodis Classe longa Problemas de DomainChecker
  117. 117. @Prodis Construtor recebe um hash como parâmetro, mas somente usa o valor de uma chave do hash. Problemas de DomainChecker
  118. 118. @Prodis Uma implementação de método que apenas chama um método privado sem passagem de parâmetros Problemas de DomainChecker
  119. 119. @Prodis Memoize hell: métodos “memoizados" que são usados como variáveis Problemas de DomainChecker
  120. 120. @Prodis Um monte de ifs: ifs com ifs com else com if com else (difícil até para explicar) Problemas de DomainChecker
  121. 121. @Prodis Código difícil para entender (internal x external checks) Problemas de DomainChecker
  122. 122. @Prodis Um método privado não usado Problemas de DomainChecker
  123. 123. @Prodis Um método de instância que cria outra instância da mesma classe Problemas de DomainChecker
  124. 124. @Prodis • Muitas responsabilidades: ✴ Validação de formato de domínio ✴ Validação de lógica de domínio ✴ Retornos com formato exclusivo para a view ✴ Faz requisições HTTP ✴ Parser de respostas HTTP Problemas de DomainChecker
  125. 125. @Prodis A classe DomainChecker introduz novos padrões e princípios
  126. 126. @Prodis Write-only code Uma vez escrito, ninguém mais consegue ler DomainChecker introduz novos padrões e princípios
  127. 127. @Prodis Close Closed Principle Fechado para modificação, mais fechado para extensão. DomainChecker introduz novos padrões e princípios
  128. 128. @Prodis Inception Pattern Onde uma instância de uma classe cria uma nova instância da mesma classe e agrega o estado da nova instância para seu próprio estado DomainChecker introduz novos padrões e princípios
  129. 129. @Prodis A classe DomainChecker provavelmente é a pior classe em Ruby que eu já vi na minha vida
  130. 130. @Prodis Como foi corrigido?
  131. 131. @Prodis
  132. 132. @Prodis Por que POG é aplicada?
  133. 133. @Prodis Falta de conhecimento Causas de POG
  134. 134. @Prodis Imaturidade no desenvolvimento de software Causas de POG
  135. 135. @Prodis Ambiente não colaborativo Causas de POG
  136. 136. @Prodis Falta de coaching Causas de POG
  137. 137. @Prodis Prazos apertados Causas de POG
  138. 138. @Prodis Por que simplificar se você pode complicar? Causas de POG
  139. 139. @Prodis Uso de “coisas legais” porque elas são legais, mesmo se elas não oferecem uma solução para o que você precisa. Causas de POG
  140. 140. @Prodis Alguns mistérios da mente humana (que não podemos explicar) Causas de POG
  141. 141. @Prodis Como evitar POG?
  142. 142. @Prodis Leia muito Como evitar POG?
  143. 143. @Prodis Como evitar POG?
  144. 144. @Prodis Mas não aprenda somente Ruby Como evitar POG?
  145. 145. @Prodis Como evitar POG?
  146. 146. @Prodis Use revisão de código Como evitar POG?
  147. 147. @Prodis Leia código de outros programadores Como evitar POG?
  148. 148. @Prodis Escreva código que você mesmo irá conseguir ler no futuro Como evitar POG?
  149. 149. @Prodis Participe de projetos open source: contribuindo, discutindo, lendo código. Como evitar POG?
  150. 150. @Prodis Coaching de programadores menos experientes (ensinar é uma boa maneira de aprender também) Como evitar POG?
  151. 151. @Prodis Não escreva código para você: escreva para a aplicação, para sua equipe. Como evitar POG?
  152. 152. @Prodis Troque experiências, pergunte. Como evitar POG?
  153. 153. @Prodis Use programação pareada (não 100% do tempo IMHO) Como evitar POG?
  154. 154. @Prodis Aprenda com erros: seus e dos outros Como evitar POG?
  155. 155. @Prodis Encare código ruim como uma oportunidade de melhorar Como evitar POG?
  156. 156. @Prodis Não encare código ruim com reclamações ou tirando sarro dos autores Como evitar POG?
  157. 157. @Prodis Este “código engraçado” causa desperdício de tempo, recursos e dinheiro Como evitar POG?
  158. 158. @Prodis Ao invés disso, mostre para os autores do código ruim o caminho certo Como evitar POG?
  159. 159. @Prodis Mostre a eles o Ruby way Como evitar POG?
  160. 160. @Prodis Obrigado! Espero que tenham gostado @Prodis
  161. 161. @Prodis https://twitter.com/prodis 
 https://github.com/prodis https://www.linkedin.com/in/prodis http://prodis.blog.br @Prodis

×