Programando com brincadeira de criança

Programando com brincadeira de criança

Publicado em: 20/4/2016

A infância, normalmente, é uma das épocas que mais gostamos de nossas vidas. Nos preocupávamos muito mais em brincar – e muitas dessas brincadeiras ajudaram a desenvolver algumas de nossas habilidades físicas e mentais, habilidades essas que possuímos até hoje.

Uma dessas brincadeiras era a tal do “Mestre Mandou”, conhece? Ela funciona da seguinte forma: uma das crianças é o mestre e as demais são os seguidores. Então o mestre começa dizendo:

– O mestre mandou!

E os seguidores respondem:

– Fazer o quê?

E então o mestre dá uma ordem e os seguidores precisam cumprí-la.

Com base nessa brincadeira (para saber mais sobre ela, clique aqui) vamos conversar um pouco sobre o “Tell don’t ask“.  Se você nunca ouviu falar, o “Tell don’t ask”  segue a mesma lógica do Mestre Mandou.

Você possui um objeto e esse objeto faz várias coisas. E, algumas dessas coisas têm condições para que o objeto faça. Complicou? Vamos exemplificar.

Imagine o seguinte caso: uma loja online, em que para adicionar um item no carrinho de compras, ele deve estar em estoque, pois não é interessante para o lojista que ele deixe de vender produtos que não possa entregar de imediato.

Show me the code!

class Cart

  has_many :products
 
  def add_product(id)
	product = Product.find(id)
	raise 'Product is not in stock' unless product.stock?
	product.add_product
  end
end
 
class Product
  STOCK_LIMIT = 10
 
  def stock
	quantity > STOCK_LIMIT
  end
 
  def add_product
	# Add Product
  end
end

Com base nesse exemplo nós aplicaremos o “Tell don’t ask“.

Perceba que a classe Cart tem um método add_product e, dentro desse método, fazemos uma validação e chamamos o método add_product do Product.

O “Tell don’t ask” fala justamente sobre isso. Caso você tenha que executar uma ação, não deve ficar perguntando a outro objeto se deve prosseguir ou não. Você deve agrupar esses comportamentos em um único lugar e, sempre que precisar executar a ação, chamar apenas o método.

Esse método se encarregará de fazer todas as verificações sem que o método que chamou fique se preocupando sobre como as coisas vão acontecer, como na brincadeira, em que

o “Tell don’t ask” apenas diz “Faça. Não importa como.”.

Aplicando o “Tell don’t ask” ficará nesse estilo:

class Cart
  has_many :products
 
  def add_product(id)
product = Product.find(id)
	product .add_product!
  end
end
 
class Product
  STOCK_LIMIT = 10
 
  def stock
	quantity > STOCK_LIMIT
  end
 
  def add_product
	# Add Product
  end
 
  def add_product!
	raise 'Product is not in stock' unless stock?
	add_product
  end
end

Você pode perceber agora que o carrinho não pergunta se o produto está em estoque para adicioná-lo. Ele apenas diz para o produto se adicionar e a verificação, se tem estoque ou não, é feita pelo próprio produto.

É recomendável aplicar o “Tell don’t ask” porque quando você deixa a regra de negócio junto com o método que a executa, está evitando fazer alterações em vários lugares em dado momento em que você precise alterar a regra de negócio.

Por exemplo, agora além do produto estar no estoque, ele precisa estar ativo para compras, pois você pode deixar ele visível na loja, mas não pode disponibilizá-lo para compras e essa mesma regra deve refletir tanto no carrinho, como na lista de desejos.

No primeiro exemplo seria algo assim:

class Cart
  has_many :products
 
  def add_product(id)
	product = Product.find(id)
	raise 'Product is not in stock' unless product.stock?
	raise 'Product is not enabled' unless product.enabled?
	product.add_product
  end
end
 
class Wishlist
  has_many :products
 
  def add_product(id)
	product = Product.find(id)
	raise 'Product is not in stock' unless product.stock?
	raise 'Product is not enabled' unless product.enabled?
	product.add_product
  end
end
 
class Product
  STOCK_LIMIT = 10
 
  def stock
	quantity > STOCK_LIMIT
  end
 
  def add_product
	# Add Product
  end
end

Aplicando o “Tell don’t ask” nosso exemplo ficará assim:

class Cart
  has_many :products
 
  def add_product(id)
	product = Product.find(id)
product.add_product
  end
end
 
class Wishlist
  has_many :products
 
  def add_product(id)
	product = Product.find(id)
product.add_product
  end
end
 
class Product
  STOCK_LIMIT = 10
 
  def stock
	quantity > STOCK_LIMIT
  end
 
  def add_product
	# Add Product
  end
 
  def add_product!
	raise 'Product is not in stock' unless product.stock?
	raise 'Product is not enabled' unless product.enabled?
	add_product
  end
end

Perceba que qualquer regra nova você aplica só dentro do método add_product! na classe Product e não mais em dois lugares, como seria no exemplo em que não é aplicado o “Tell don’t ask” que seria necessário trocar tanto na classe Cart como na Wishlist.

Gostou da dica? ficou com alguma dúvida? Deixe nos comentários.

Publicado originalmente em Blog Locaweb