37
MELHORANDO SEU CÓDIGO Law of Demeter Tell, don’t ask

Melhorando seu código com Law of Demeter e Tell don't ask

Embed Size (px)

Citation preview

MELHORANDO SEU CÓDIGO

Law of Demeter

Tell,

don’t ask

Sobre mim@nelson_senna

https://nelsonsar.github.io

DRY?

YAGNI?SOLID?

TELL DON’T ASK

LAW OF DEMETERDDD!

–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.”

DE FORMA PRÁTICA

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

E ISSO TEM UM CHEIRINHO…

–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.”

NÃO SE CONVENCEU?

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

TELL, DON’T ASK

–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

LAW OF DEMETER

–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

NULL OBJECT

–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

DESVANTAGENS E CUIDADOS

https://github.com/troessner/reek

PRINCÍPIOS DEVERIAM AJUDAR E NÃO

CONFUNDIR

DÚVIDAS

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