tdc2016poa | trilha ruby - melhorando seu código com law of demeter e tell don't ask
TRANSCRIPT
–Alan Kay
“The key in making great and growable systems is much more to design how its modules communicate rather than what
their internal properties and behaviors should be.”
class Paperboy attr_reader :wallet
def initialize(wallet) @wallet = wallet end
def receive_from(customer, amount) if customer.wallet.try(:amount).to_f > amount @wallet.amount = amount customer.wallet = customer.wallet.amount - amount else nil end end end
class Paperboy attr_reader :wallet
def initialize(wallet) @wallet = wallet end
def receive_from(customer, amount) if customer.wallet.try(:amount).to_f > amount @wallet.amount = amount customer.wallet = customer.wallet.amount - amount else nil end end end
class Paperboy attr_reader :wallet
def initialize(wallet) @wallet = wallet end
def receive_from(customer, amount) if customer.wallet.try(:amount).to_f > amount @wallet.amount = amount customer.wallet = customer.wallet.amount - amount else nil end end end
–Ruby Science
“Referencing another object’s state directly couples two objects together
based on what they are, rather than on what they do.”
describe Paperboy do describe '#receive_from' do let(:paperboy) { described_class.new(Wallet.new(0)) }
context 'when customer has enough money to pay' do it 'add due amount to wallet' do customer = double allow(customer).to receive(:wallet).and_return(Wallet.new(10))
paperboy.receive_from(user, 5)
expect(paperboy.wallet.amount).to eq(5) end end end end
describe Paperboy do describe '#receive_from' do let(:paperboy) { described_class.new(Wallet.new(0)) }
context 'when customer has enough money to pay' do it 'add due amount to wallet' do customer = double allow(customer).to receive(:wallet).and_return(Wallet.new(10))
paperboy.receive_from(user, 5)
expect(paperboy.wallet.amount).to eq(5) end end end end
describe Paperboy do describe '#receive_from' do let(:paperboy) { described_class.new(Wallet.new(0)) }
context 'when customer has enough money to pay' do it 'add due amount to wallet' do customer = double allow(customer).to receive(:wallet).and_return(Wallet.new(10))
paperboy.receive_from(user, 5)
expect(paperboy.wallet.amount).to eq(5) end end end end
–Reek doumentation
“Feature Envy occurs when a code fragment references another object more often than it
references itself, or when several clients do the same series of manipulations on a particular type of
object.”
def associate_user @order ||= current_order if try_spree_current_user && @order if @order.user.blank? || @order.email.blank? @order.associate_user!(try_spree_current_user) end end end
–Martin Fowler
“It reminds us that rather than asking an object for data and acting on that data, we should instead tell an object what
to do.”
class Order def apply_discount(promotion) if promotion.eligible?(shipment) promotion.activate(shipment) end end end
class Order def apply_discount(promotion) if promotion.eligible?(shipment) promotion.activate(shipment) end end end
–Ruby Science
“The law restricts how deeply a method can reach into another object’s dependency
graph, preventing any one method from becoming tightly coupled to another
object’s structure.”
class Paperboy attr_reader :wallet
def initialize(wallet) @wallet = wallet end
def receive_from(customer, amount) if customer.wallet.try(:amount).to_f > amount @wallet.amount = amount customer.wallet = customer.wallet.amount - amount else nil end end end
class Paperboy attr_reader :wallet
def initialize(wallet) @wallet = wallet end
def receive_from(customer, amount) self.wallet.add(customer.pay(amount)) end end
–Martin Fowler
“Instead of returning null, or some odd value, return a Special Case that has the same interface as what the
caller expects.”
def associate_user @order ||= current_order if try_spree_current_user && @order if @order.user.blank? || @order.email.blank? @order.associate_user!(try_spree_current_user) end end end
def try_spree_current_user if respond_to?(:spree_current_user) spree_current_user elsif respond_to?(:current_spree_user) current_spree_user else Guest.new end end
REFERÊNCIAS• http://www.dan-manges.com/blog/37
• http://www.virtuouscode.com/2011/06/28/do-or-do-not-there-is-no-try/
• http://gmoeck.github.io/2011/09/28/why-you-should-care-about-information-hiding.html
• http://blog.davidchelimsky.net/blog/2006/11/27/fighting-the-urge-to-ask/
• http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf
• martinfowler.com/bliki/TellDontAsk.html
• https://adamcod.es/2013/11/22/tell-dont-ask.html
• https://pragprog.com/articles/tell-dont-ask
• https://edelpero.svbtle.com/most-common-mistakes-on-legacy-rails-apps
• http://www.mockobjects.com/2006/10/tell-dont-ask-and-mock-objects.html
• https://robots.thoughtbot.com/tell-dont-ask
• https://skillsmatter.com/skillscasts/8611-tell-dont-ask
• https://www.javacodegeeks.com/2015/11/tell-dont-ask.html
• http://natpryce.com/articles/000777.html
REFERÊNCIAS• http://martinfowler.com/bliki/GetterEradicator.html
• http://verraes.net/2014/09/objects-as-contracts-for-behaviour/
• https://medium.com/skyfishtech/retracing-original-object-oriented-programming-f8b689c4ce50#.yk9k1s7ku
• http://brightonruby.com/2016/the-point-of-objects-john-cinnamond/
• https://github.com/spree/spree/blob/master/core/app/models/spree/promotion_handler/page.rb
• https://github.com/troessner/reek/blob/master/docs/Feature-Envy.md