Você usa DTO/TO/VO em aplicações não distribuídas ?

Esta semana eu estava discutindo com alguns colegas de trabalho, sobre a arquitetura de alguns sistemas J2EE que tínhamos (o desprazer) de manter. Até certo momento estávamos concordando em todos os pontos fracos da abordagem utilizada nestes sistemas. Quando de repente um deles me surpreende com: “Um projeto J2EE bem feito, pra mim, tem que ter no mínimo…”. Começou então a discussão:

Colega A: Um projeto J2EE bem feito, para mim, tem que haver no mínimo um Façade, tem que ter DAOs e … DTOs.

Eu: DTOs? Depende…

Colega A: Como assim depende? Um projeto sem DTO?

Eu: Sim, sem DTO! Não há motivo para utilizarmos um DTO (Na verdade falávamos de Transfer Objects) na maioria das aplicações que desenvolvemos.

Colega B: Eu devo ou não usar DTOs,… TOs,… (arrg!) isso aí que vcs estão falando?

Colega B: Decidam-se…

Colega A: Ele deve ter visto isso em algum lugar e acha que pode escrever uma aplicação J2EE sem usar um DTO. Neste momento eu percebi que meu colega não havia gostado muito da idéia de ter seu modelo de arquitetura questionado. Vamos seguindo…

Eu: Alto lá! Eu sei para que servem os Transfer Objects e uma aplicação web onde as camadas residem na mesma JVM (a maioria dos projetos) não é um caso onde devemos implementá-los. Acompanhe meu raciocínio: A intenção do padrão Transfer Object é transferir dados entre tiers (e não layers) visando reduzir os custos das chamadas remotas num cenário distribuído. Logo, nossa aplicação não precisa de TOs!

Colega B
: hmmmm

Colega A
: Tudo bem, mas então como iremos mapear as entidades do banco? O Hibernate precisa de objetos para serem mapeados… e aí? Cara,… eu aprendi e sempre trabalhei criando uma classe que é um espelho de uma tabela do banco (TO) e uma classe contendo as regras de negócio, as validações (BO).

Eu: Sim, concordo com você! O Hibernate precisa de objetos, e objetos “de verdade” têm dados + comportamento. Ao criar a dupla ClienteTO + ClienteBO você está dividindo o domínio (objeto) Cliente em duas classes desnecessariamente. Veja a definição de um Acemic Domain Model do Matin Fowler.

Você trabalha com os TO como se fossem registros de uma tabela (um resultSet) as regras de negócio e as validações você escreve no BO (Business Object) e repete onde quer que você precise tratar dados do seu TO. Isso é programação estruturada, não é OOP! Eu não sei o porquê, mas entendo que este não seja um pensamento só seu. Já vi diversos profissionais programarem dessa forma (por uma interpretação errada dos padrões, ou muitas vezes obrigados a seguir uma arquitetura de referência adotada em sua empresa), eu mesmo já programei assim!

Colega A: É verdade…

Eu: Já li diversos textos e discussões em fóruns onde algumas pessoas ainda tentam, mas sem sucesso, justificar o uso de TO numa aplicação não distribuída. É a febre dos patterns! Às vezes você cria situações para justificar a injeção (palavra na moda :) ) de um pattern em seu design? Evite isso.

Colega A: Sim,… e o que vc passa para sua camada de apresentação? Se não tenho mais DTOs eu vou passar os objetos de domínio?

Eu: Sim! Você tem algum bom motivo para não passar os “BOs” ? Se for por questões de acoplamento, observe que um diagrama com TOs é mais complexo e tem mais acoplamento do que uma versão sem TOs. Se a questão é proteção de alguns dados e/ou métodos, se você programou sua View para interfaces e não para classes concretas, pode usar interfaces de negócio mais restritivas em relação à API do seu componente expondo somente o necessário (Lembrei das Virtual Interfaces de Web Services do SAP NW :) ).

ComSemTransferObject

Os colegas citados acima existem (!) e foram convidados a comentar este post, veremos se eles continuam pensando da mesma forma :)

Fontes sobre o assunto:
Martin Fowler, http://www.martinfowler.com
J2EE AntiPatterns
Phillip Calçado “Shoes” (ThoughtWorks), http://fragmental.com.br/wiki/index.php?title=Fantoches
Discussão no GUJ: http://www.guj.com.br/posts/list/28889.java

11 Respostas

  1. Laérico, os melhores assuntos são os mais polêmicos. Ou seja, vejo que começou bem o blog.
    Eu também só conhecia o modelo de programação em camadas, usando o DTO. Mas, não acredito que eu seja o mais indicado a debater este assunto, não estudo muito sobre programação.
    Já fiz a referência do seu novo espaço lá no blog. Espero que continue compartilhando bons artigos por aqui!

    Abraços!

  2. Eu concordo com o fato de em muitos casos não ser necessário a utilização de DTO. Em muitas aplicações os contêineres WEB e EJB estão sobre a mesma VM. Neste caso nada mais óbvio que efetuar as chamadas através das interfaces locais e passar a própria interface Local para a interface sem a necessidade de escrever desnecessariamente um DTO.

  3. Bom post Laercio, só algumas questões que tenho… por exemplo no seu diagrama o que Seria o Aluno ? para que ele serve ? e a mesma pergunta para Façade em questão…

    Não sei se entendi errado,… então vou tentar explicar com código o que entendi, ok ? então você pode confirma se esta certo :)

    Temos o objeto Cliente:

    public class Cliente {
    //dados do cliente
    //normal gets and sets
    //metodo de negocio aqui ?
    }

    então poderia existir um cliente.getLimiteDeCredito() ?

    mais imagine um sistema real normalmente este limite de credito poderia ser bem complicado, poderia haver tipos diferentes de cliente….

    essa tecnica de juntar tudo no mesmo objeto me parece meio arriscado…, não ?

    valeu…

  4. Olá Alex!

    “Bom post Laercio,”

    Obrigado! :)

    “só algumas questões que tenho… por exemplo no seu diagrama o que Seria o Aluno ? para que ele serve ? e a mesma pergunta para Façade em questão…”

    A classe Aluno modela um conceito do nosso domínio – no exemplo do post, um aluno. Ele é nosso objeto de negócio. Quanto ao façade, sem mistérios. Ele seria o responsável apenas por executar um conjunto de passos relacionados ao Aluno, facilitando o trabalho para os clientes do seu objeto – é freqüente em alguns sistemas, encontrar a relação 1-1 entre façade e objeto de negócio. Segue um exemplo simples:

    class AlunoFacade {
    public Aluno obterAlunoPorId(Object id) throws RegistroIniexistente {
    DAOFactory daoFactory = …
    AlunoDAO dao = daoFactory.criarAlunoDAO();
    return dao.obterPorId(id);
    }
    }

    “então poderia existir um cliente.getLimiteDeCredito() ?”

    Um objeto rico deve ter estado e comportamento (dados e métodos respectivamente). Sendo assim, nosso objeto Aluno deve ser responsável por manter-se válido e prover métodos que alterem seu estado. Não existe uma boa razão pela qual vc desejasse separar o estado e o comportamento (de um mesmo conceito do domínio) em objetos diferentes. Teria?

    “mais imagine um sistema real normalmente este limite de credito poderia ser bem complicado, poderia haver tipos diferentes de cliente….”

    Imagino! Mas vc pode facilmente alterar comportamentos do seu objeto usando composição (preferencialmente) ou usando herança.

    “essa tecnica de juntar tudo no mesmo objeto me parece meio arriscado…, não ?”

    Arriscado se não houver uma separação clara das responsabilidades de cada classe. ;)

    []s

  5. [...] comuns para persistência e negócio. É comum nestes casos ver modelos anêmicos usando o conjunto BO/DTO-VO-TO/DAO. Então fica a [...]

  6. Laércio,
    Achei muito interessante a questão que você levantou. Muitas vezes adotamos os padrões sem refletir sobre a real necessidade ou compatibilidade e abrimos mão de analisar os beneficios daquele padrão para as nossas aplicações. Eu sou adepto do principio KISS e, confesso, que apesar de seguir muitos desses padrões cegamente, me questiono sobre a real necessidade de algumas coisas. Eu já desenvolvi muitas aplicações pequenas, principalmente WEB, e me pergunto se não tem coisa demais fazendo coisa de menos? Aplicações administrativas pequenas geralmente são compostas em grande parte por simples CRUDs com pouquissima regra de negocio e complexidade. Você me fez repensar meus conceitos para essas aplicações! Eu, apesar de ainda utilizar um VO anêmico, mandei pro espaço o BO nas aplicações menores, simplifico e generalizao ao máximo os DAOs (graças ao hibernate e nhibernate) e o pouco de regras de negócio insiro no Façade, que nos meus sistemas é a interface única e principal com a regra de negócio. Não sei se é uma abordagem popular mas mantem tudo estupidamente simples e legivel. Eu sou obcecado por padrões, legibilidade, programação bem estruturada e não acho que essa arquitetura esteja prejudicada, exceto, pelo fato, de concordar que talvez essa separação seja desnecessária. Alguns programadores se acostumaram tanto à esta abordagem, que foi desenhada para grandes aplicações (bazuca para matar mosca), que não acham a sua proposta natural, mas imagine se ao invés de uma implementação do LinkedList você tivesse um LinkedList e um LinkedListBO?! :) Ou o mesmo para um Calendar?!
    Bom, desculpe o comentário com tamanho de post, mas seu post me empolgou! :D

  7. Cara. ..gostei do seu post … bastante interessante….

    mas so uma coisa …. usando o padrão DAO, a necessidade do uso de TOs é clara, pois caso você utilize o objeto de domínio da maneira que você falou, você fere o conceito das tiers, pois acopla à camada de acesso a dados ( o objeto de acesso a dados ) informações sobre o seu negócio. Ou seja, uma tier de mais baixo nível acessando um tier de nível superior, o que não é legal em muitos projetos, quando a reutilização dos DAOs é crítica….

    mas enfim…..bem legal o artigo mesmo !!!! parabéns !!!

    Abraços

  8. Olá Leandro, obrigado pelo comentário. :)

    “mas so uma coisa …. usando o padrão DAO, a necessidade do uso de TOs é clara, pois caso você utilize o objeto de domínio da maneira que você falou, você fere o conceito das tiers, pois acopla à camada de acesso a dados ( o objeto de acesso a dados ) informações sobre o seu negócio. Ou seja, uma tier de mais baixo nível acessando um tier de nível superior, o que não é legal em muitos projetos, quando a reutilização dos DAOs é crítica….”

    Você está falando de layer, certo? Tiers são camadas separadas fisicamente, neste cenário os DTOs “poderiam” ser uma opção (dependendo do contexto).

    Quanto a Dependency Direction (SoC), eu concordo com vc. As implementações mais comuns de um DAO, em última análise, quebram este princípio nas camadas empilhadas por se tratar de um *interesse transversal*.

    A maioria dos DAOs que escrevemos são Data Mappers responsáveis por persistir e recuperar nossos objetos de domínio de um banco de dados. Nestes casos, estes objetos *são dependentes* e construídos sob um modelo de domínio específico. Ou seja, alterações na interface do objeto de domínio serão refletidas no DAO (e isto faz sentido mesmo se estivéssemos referenciando um DTO).

    Uma opção é usar o Dependency Inversion Principle para solucionar este impasse. Basicamente, faça seus objetos de domínio *dependerem de uma abstração* (um repository na domain layer), injetando as implementações concretas (persistência) dessa abstração no domínio (usando AOP, DI,…).

    Quando este recurso precisa ser reutilizado entre aplicações distintas, é altamente aconselhável fazer uso de componentes e APIs mais genéricos. Frameworks ORM são um bom exemplo disto, evitando ter que criar Mappers “na mão”. Estes sim, são totalmente independentes de um domínio e te livram de ter que criar quilos de código para isso.

    Enfim, uma modelagem anêmica não é, nem de longe, a melhor opção. ;)

    []s

  9. Acho que essa discussão é muito interessante e deveria ser continuada num ambiente mais apropriado. Que tal leva-la para a lista javabahia?

  10. - “mais imagine um sistema real normalmente este limite de credito poderia ser bem complicado, poderia haver tipos diferentes de cliente….”

    R: Utilize o padrão “Composto”.

    “e objetos “de verdade” têm dados + comportamento”

    Sim, mas objetos do dominio, ou conceito do mundo real chamadas de Classe Conceitual.

    Mas temos objetos chamados de Classe de Software – Classe que representa uma perspectiva de especificação ou implementação de um elemento de software, independente do processo ou método. Utilize o padrão Invensão Pura, sem obrigatoriamente utilizar um posfixo DTO, VO ect.

    Uma classe anêmica só é anêmica se forçada.
    Martin Fowler não expandiu tanto seu conceito assim.

Deixe um comentário