The document discusses poor quality code examples in Ruby. It begins by providing context about the speaker and their experience developing applications in Ruby and other languages. Several examples of poor code are then presented and analyzed, including masking credit card numbers, obscure code flows, and issues with naming conventions. Alternate implementations are proposed to improve the code quality by addressing the identified issues.
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.
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
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
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
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
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
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
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
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. @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. @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. @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. @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. @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
78. @Prodis
class TransactionResponseParser < ResponseParser
private
# specific transaction methods omitted
end
class AccountResponseParser < ResponseParser
private
# specific account methods omitted
end
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
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
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. @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. @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. @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. @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. @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. @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. @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. @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. @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. @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. @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. @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
123. @Prodis
Um método de instância
que cria outra instância
da mesma classe
Problemas de DomainChecker
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
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