terça-feira, maio 20, 2008

Princípios de OO segundo Alan Knight (e Dilbert) (parte 1)

(nossa como faz tempo que não posto... :p) Faz uns anos eu achei um artigo artigo obscuro escrito por Alan Knight por volta de 2000 ou 2001 que é um excelente resumo de como deve ser um bom código orientado a objetos. O mais interessante é que o artigo faz analogia aos princípios "Dilbert", e por incrível que pareça, a analogia encaixa como uma luva. O texto é curto e muito divertido, recomendo a leitura! Como sempre mostro esse artigo pra todo mundo que eu conheço, achei que já era hora de citar ele no blog e fazer um resumo em português pra quem não conhece bem o gringolês. Como posts grandes ninguém lê, vou postando os princípios aos poucos. Nota: AS IDÉIAS AÍ EMBAIXO NÃO SÃO MINHAS, OKAY? EU GOSTO MUITO DELAS, MAS O AUTOR ORIGINAL É O "TIUZÃO TOP FODA" ALAN KNIGHT! Avisados? Ótimo! Senão depois o TaQ briga comigo por estar levando crédito por idéias alheias :).

Princípio 1: Nunca faça nada que alguém possa fazer para você.

Esse é basicamente o princípio do "tell, don't ask". Basicamente, objetos não podem ser caras legais. Nada de "Olha, preciso do total dos custos desde o começo do mês, mas não se incomode, me dê os dados aí que eu mesmo faço o cálculo, não deve ser muito complicado, não é?"
  total = centro_de_custo.itens.inject(0) do|soma, item| 
    if item.data > Date.parse('2008-05-01')
      soma += item.valor 
    else
      soma
    end
  end
Objetos devem ser grandes FDPs. Objeto bom é grosso como seu chefe: "Cara, quero o total dos custos desde o começo do mês! Não quero nem saber e não me interessa como você calcula isso, quero o resultado, e quero JÁ!".
  total = centro_de_custo.total_desde('2008-05-01')
Em Java, vejo muito uma coisa um pouco mais esquisita, normalmente envolve um DAO, injeção de dependência e costumeiramente um Date que não se pode construir diretamente pois o construtor está "deprecated":
  // getCentroDeCustoDAO foi alimentado antes pelo Spring
  // e "new Date" costuma ser gerado via Calendar, pq esse
  // construtor está deprecated faz tempo...
  List itens = getCentroDeCustoDAO().procurarPorDataDesde(new Date(2008, 4, 1));
  BigDecimal resultado = new BigDecimal(0);
  for(Item item : itens) {
    resultado = resultado.add(item.getCusto());
  }
Mesmo que você goste muito desse padrão, seria um pouco melhor do jeito abaixo. Embora já tenha ouvido que isso é regra de negócio e não deveria ser feita no DAO.
  // getCentroDeCustoDAO foi alimentado antes pelo Spring
  // e "new Date" costuma ser gerado via Calendar, pq esse
  // construtor está deprecated faz tempo...
  BigDecimal resultado = getCentroDeCustoDAO().calcularCustoTotalPorDataDesde(new Date(2008, 4, 1));
"Tell, don't ask" <= "Mande, não peça"...