TDA (Tell Don't Ask)
Introdução
A visão original de Kay para OOP não era "objetos com dados públicos que outros manipulam", era objetos que trocam mensagens e decidem sozinhos o que fazer com elas. Tell, Don't Ask é basicamente um resgate dessa ideia original, porque com o tempo muita gente passou a usar OOP como "structs com getters e setters", perdendo o encapsulamento de verdade.
Ideia Central
Exemplo do Cliente e Carteira
Ask - Eu PERGUNTO o saldo, e EU decido o que fazer com ele:
if (cliente.carteira.saldo >= 50) {
cliente.carteira.saldo -= 50;
} else {
console.log("saldo insuficiente");
}
Tell - Eu DIGO pro cliente pagar, e ELE decide o que fazer:
// "Tell" - eu DIGO pro cliente pagar, e ELE decide o que fazer
cliente.pagar(50);
class Cliente {
carteira: Carteira;
pagar(valor: number) {
if (this.carteira.saldo < valor) {
throw new Error("saldo insuficiente");
}
this.carteira.saldo -= valor;
}
}
Repare a diferença de responsabilidade: No "Ask", quem chama o código precisa saber a regra ("se o saldo for menor, não pode pagar") e tomar a decisão sozinho. No "Tell", o próprio objeto conhece sua regra e decide por dentro. Quem chama só diz o que quer que aconteça.
Por que "perguntar" é perigoso
Pensa no "Ask" espalhado pelo sistema: toda tela, todo botão, todo endpoint que cobra do cliente vai ter que copiar essa mesma verificação de saldo:
if (cliente.carteira.saldo >= valorDoCarrinho) { ... }
if (cliente.carteira.saldo >= valorDaAssinatura) { ... }
if (cliente.carteira.saldo >= valorDoBoleto) { ... }
Se um dia a regra mudar (por exemplo, "clientes VIP podem ficar com saldo negativo até -R$100"), você precisa caçar todos esses lugares e mudar um por um. É praticamente garantido que algum lugar vai ser esquecido - e aí seu sistema tem um bug de regra de negócio inconsistente.
Com "Tell", a regra mora em um lugar só (Cliente.pagar). Mudar uma vez, resolve todo o sistema.
Como isso conecta com Law of Demeter
Os dois princípios andam juntos, mas resolvem problemas ligeiramente diferentes:
- Law of Demeter: não atravesse a estrutura interna de outros objetos (
a.b.c). - Tell, Don't Ask: não extraia dados de um objeto pra decidir algo fora dele - mande o objeto decidir.
Na prática, quando você aplica bem "Tell, Don't Ask", quase sempre acaba respeitando Law of Demeter de graça - porque você para de precisar alcançar o carteira.saldo de fora.
O sinal de alerta pra reconhecer
Pergunte-se, olhando pro código: "Estou pegando um dado de dentro de um objeto só pra, logo em seguida, tomar uma decisão (if) ou fazer uma conta com esse dado?"
Se sim, é sinal de "Ask". Pergunte então: "quem deveria saber essa regra: eu (quem está chamando) ou o objeto dono do dado?" Quase sempre é o objeto dono.
// Sinal de alerta: pegou o dado (idade) e decidiu por fora
if (usuario.idade >= 18) {
liberarCompra();
}
// Melhor: quem sabe a regra de maioridade é o próprio usuário
if (usuario.podeComprar()) {
liberarCompra();
}
Quando NÃO aplicar ao pé da letra
- Código que só exibe dados (uma tela mostrando o saldo do cliente) precisa "perguntar" - não tem decisão de negócio envolvida, só exibição. Tell, Don't Ask é sobre decisões e comportamento, não sobre leitura pura de dados para exibir.
- Structs/DTOs (objetos que só carregam dados entre camadas, tipo resposta de API) não precisam desse princípio - eles não têm comportamento por definição.
Comments
No comments yet. Start the discussion.