Refatoração de Camadas para utilização DTO + CDI e Rich Domain Model

37 respostas
A

Estou desenvolvendo um projeto core que será utilizado em vários outros projetos. Será gerado um .jar dele etc…
Este core, deve prover a base para persistência, e ainda alguns modelos de domínio que são comuns a todas aplicações que vão utilizar ele.
Vou tratar aqui da básica: Cadastro de Pessoa.
Atualmente estou trabalhando com as seguintes “camadas” e classes:
No core:
1 - DAO: Contém a classe AbstractHibernateDAO onde é feito todas as operações que serão usadas pelos Repository.
2 - Repository: Contém a classe AbstractRepository com os cruds extendendo de AbstractHibernateDAO, e no caso PessoaRepositroy que obviamente extende AbstractRepository, em PessoaRepository contém por exemplo o método buscarPessoasPorMunicipio(Municipio municipio).
3 - Model : contém as Entity por exemplo Pessoa, Endereco, Municipio. (estes models atualmente estão servindo apenas para mapeamento O/R “anêmicos”)
4 - Service: classe PessoaService, básicamente só faz chamadas aos Repository. (sim não faz sentido ter, preciso mudar isso, minha intenção era que os outros projetos não acessem os Repository diretamente)

Nos projetos que usam o core:
Projeto desktop1:
1 - Models : seus models específicos,
2 - Repository : Implementação do AbstractRepository para seus models.
3 - Presenter: recebe o PessoaService (gostaria de usar eventos do cdi), e trabalha com ele entre a view. Manipula diretamente o model Pessoa. (gostaria de trabalhar com DTO e Wrapper)

Projeto Web1:
1 - Models : seus models específicos,
2 - Repository : Implementação do AbstractRepository para seus models.
3 - Controller: recebe o PessoaService (gostaria de usar eventos do cdi), e trabalha com ele entre a view. Manipula diretamente o model Pessoa. (gostaria de trabalhar com DTO e Wrapper)

Alguém consegue indicar um caminho para seguir com as alterações?

Segue as Classes Envolvidas:

core.model

class Pessoa{
     //estou omitindo os mapeamentos O/R
     Long id;
     String nome;
     //estes enderecos estão sendo inseridos ou atualizados por CASCADE, tenho que mudar isso principalmente no Update
     List<Endereco> enderecos;

     //getters e setters

     // TODO enriquecer esta entity para evitar o modelo Anêmico 
}
class Endereco{
     //estou omitindo os mapeamentos O/R
     Long id;
     Pessoa pessoa;
     Municipio municipio;
     String bairro;
     String rua;

     //getters e setters

     // TODO enriquecer esta entity para evitar o modelo Anêmico 
}
class Municipio{
     //estou omitindo os mapeamentos O/R
     Long id;
     String descricao;

     //getters e setters

     // TODO enriquecer esta entity para evitar o modelo Anêmico talvez aqui não tenha o que fazer
}

Repository

class PessoaRepository extends AbstractRepository<Pessoa, Long>{

   //métodos crud basicos estão na classe AbstractRepository
   public List<Pessoa> buscarPessoasPorMunicipio(Muncipio municpio){
         List<Pessoa> list = null;
         //query omitida
         return list;
   }
}
class EnderecoRepository extends AbstractRepository<Endereco, Long>{

   //métodos crud basicos estão na classe AbstractRepository
   // não tem nada específico, talvez Implementação desnecessária?
}
//esta classe se justifica para isolar os projetos core entre desktop1 e web1?
class PessoaSerivce{
       @Inject
       PessoaRepository  repository;
       // aqui talvez devesse receber um DTO Válido
      public cadastrar(Pessoa pessoa){
            try{
                repository.gravar(pessoa);
            } catch (Exception e){
                   throw new ExcessaoAoGravar(e);
            }
      }
}

Projeto Web1
Controller

class PessoaController{

      @Inject PessoaService service;

       @Get("/pessoa")
       public void form(){
       }
       @Consumes(value = { "application/json", "application/x-www-form-urlencoded" }) 
       @Post("/pessoa")
       //preciso trocar pra DTO pois pode vir por json e isso pode ser um problema pois por ex. usa Reflection para deserializar
       public void gravar(Pessoa pessoa){
             //preciso validar
             service.gravar(pessoa);
       }
}

37 Respostas

pfk66

Ter um core que sabe como persistir acho que tudo bem, o serviço ficaria acessível através de uma operação do domínio e não um cadastro.

Um core que provê persistência me parece estranho.

Rafael_Guerreiro

Vamos por partes.

b[/b] Eu não gosto de criar DAOs/Repositories genéricos com o intuito de “reaproveitar” os métodos. Isso, geralmente, acaba em código mal-feito. Por exemplo, suponha que você tem uma entidade de Países, você tem um PaisDAO aonde você implementa o select. Mas você não quer que tenha os métodos save, update e delete. Só que se você extender AbstractHibernateDAO, você vai ter esses métodos.
A solução mais elegante possível é você usar o Composite-pattern.
Você só pode usar herança quando você conseguir responder a pergunta: “É um?”.
Exemplos:
[list]PaisDAO é um AbstractHibernateDAO? Não, pois é de país, não de abstractHibernate…[/list]
[list]UserDAO é um AbstractHibernateDAO? Não, pois é de user, não de abstractHibernate…[/list]
A solução com o composite seria mais ou menos assim:

public UserDAO {

    private final HibernateGenericDAO&lt;User, Long&gt; delegate;

    public UserDAO (Session session) {
        this.delegate = new HibernateGenericDAO&lt;User, Long&gt;(session);
    }

    public User save(PersistentUser dto) {
        return delegate.save(dto);
    }

// Não quero os outros métodos. E está tudo bem na minha implementação.
}

Para isso funcionar, o seu AbstractHibernateDAO não pode ser abstract (por isso mudei o nome dele para HibernateGenericDAO)
O mesmo vale para o Repository, e qualquer outro tipo de classe que você for fazer. Se você, olhando para os nomes das classes, conseguir responder aquela pergunta, é por que você deve usar herança. Você vai ver que é raro usar herança.
Ah, muitas pessoas das antigas, por conta desse problema da herança, quando não queria que um método fosse invocado, sobrescrevia o método e implementava ele assim:

Ué, se eu não posso invocar, por que ele existe? A própria API do Java tem isso nas classes mais antigas… =S

b[/b] Modelos anêmicos. O nome é até que chique, mas para mim só quer dizer uma coisa: é uma classe que não tem comportamento.
Modelo anêmico, geralmente é uma classe que tem uma pancada de atributos e seus respectivos getters e setters. Getters e setters são os maiores inimigos. Getters costumam vazar encapsulamento, setter então, você perde controle do seu modelo.
Somente sobre isso tem bastante coisa na internet. Mas esse post é muito bom para entender um pouco (e olha que ele é de 2006!!!). Você deveria devorar esse blog de ponta a ponta, tem MUITA coisa lá, desde arquitetura até como otimizar o seu dia a dia.
Apenas listando um exemplo em que o getter pode ser problemático, teste essas classes:

public class MinhaEntidade {
    private List&lt;String&gt; nomes;

    public MinhaEntidade(List&lt;String&gt; nomes) {
        this.nomes = new ArrayList&lt;String&gt;(nomes); // Criando uma cópia.
    }

    public List&lt;String&gt; getNomes() {
        return nomes;
    }
}
public static void main(String args[]) {
    MinhaEntidade obj = new MinhaEntidade(Arrays.asList("a", "b", "c"));

    List&lt;String&gt; nomes = obj.getNomes();
    System.out.println(nomes); // [a, b, c]
    nomes.clear()
    nomes.add("outro nome");

    System.out.println(nomes); // [outro nome]
    System.out.println(obj.getNomes()); // [outro nome]
}

** Vou continuar mais tarde, está ficando muito grande **

A

O core Produz a Configuration do hibernate, e dispara um evento.
O core Produz a SessionFactory com ApplicationScoped usando a Configuration injetada
O core Produz a Session também usando a SessionFactory injetada.
O core possui o AbstractRepository com operações de crud e FindBuilder pra criar queries de maneira fluente.

Assim os projetos que usam ele precisam:
ter o hibernate.cfg no seu resources com os parametros da conexão.
Observar o evento de configuração e adicionam as Entity específicas.
E aí só criar os Repository extendendo AbstractRepository

Isso que eu quis dizer com Prover base para persistência

A princípio está funcionando certo essa parte.

icarocd

do jeito sendo montado vejo uma chance alta de ter muito boilerplate e baixa produtividade tambem

-service repository e dao os tres achei muito overkill. A nao ser que haja uma razao muito forte, isso vai atrapalhar bem mais que ajudar

-service nao deve ser por entidade, mas por assunto. entidade mais fraca cabe perfeitamente em service referente ao assunto que a contem

-dto e wrapper nao usar via de regra mas apenas em casos pontuais e se houver necessidade. seu model nao ser anemico diminuiria dependencia destes tipos de classe

A

Rafael Guerreiro:
Vamos por partes.

b[/b] Eu não gosto de criar DAOs/Repositories genéricos com o intuito de “reaproveitar” os métodos. Isso, geralmente, acaba em código mal-feito. Por exemplo, suponha que você tem uma entidade de Países, você tem um PaisDAO aonde você implementa o select. Mas você não quer que tenha os métodos save, update e delete. Só que se você extender AbstractHibernateDAO, você vai ter esses métodos.
A solução mais elegante possível é você usar o Composite-pattern.
Você só pode usar herança quando você conseguir responder a pergunta: “É um?”.

Concordo em partes, eu vejo muito menos entidades que não podem ter Save, Update ou Delete do que as que podem.
E se você chamou o método Save é porque ele precisa ser implementado. No caso do “generic” ele já estaria. Se você não quer que o País seja excluído, por que tem o Botão excluir na tela do usuário, chama o excluir no controller, e chama o excluir no DAO?

Entendi seu ponto de vista mas acho que no caso específico do DAO o composit não me parece muito útil.

Rafael_Guerreiro

Algumas coisas para você ler:

Do blog da caelum, sobre esse e alguns outros conceitos de design.
http://blog.caelum.com.br/como-nao-aprender-orientacao-a-objetos-heranca/
http://blog.caelum.com.br/effective-java-segunda-edicao/
http://blog.caelum.com.br/possibilidades-de-design-no-uso-do-seu-generic-dao/
http://blog.caelum.com.br/principios-do-codigo-solido-na-orientacao-a-objetos/

http://stackoverflow.com/questions/38820/which-class-design-is-better
http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance?answertab=votes#tab-top

pfk66

andersonscherrer:
O core Produz a Configuration do hibernate, e dispara um evento.
O core Produz a SessionFactory com ApplicationScoped usando a Configuration injetada
O core Produz a Session também usando a SessionFactory injetada.
O core possui o AbstractRepository com operações de crud e FindBuilder pra criar queries de maneira fluente.

Assim os projetos que usam ele precisam:
ter o hibernate.cfg no seu resources com os parametros da conexão.
Observar o evento de configuração e adicionam as Entity específicas.
E aí só criar os Repository extendendo AbstractRepository

Isso que eu quis dizer com Prover base para persistência

tudo importante do ponto de vista da implementação, mas não é essencial (core) do ponto de vista do negócio.

pfk66

ícaro, ele quer usar DTO pra comunicar com o cliente em outro local, e não apenas trafegar dados entre camadas, ou seja, ele quer criar seu próprio protocolo RPC binário para computação distribuída, usando uma interface baseada em json!

A

pfk66:
ícaro, ele quer usar DTO pra comunicar com o cliente em outro local, e não apenas trafegar dados entre camadas, ou seja, ele quer criar seu próprio protocolo RPC binário para computação distribuída, usando uma interface baseada em json!

Basicamente isso, estou usando o VRaptor e o Gson para receber e deserializar o JSON, assim se eu deixar o objeto Pessoa direto, eu não tenho controle do que pode chegar no meu JSON pois o Gson utiliza reflection para deserializar. Assim eu posso usar um DTO como o Rafael sugeriu. E depois em algum ponto criar a entity Pessoa para persistir ou qualquer outra coisa.

A

Rafael Guerreiro:
Algumas coisas para você ler:

Do blog da caelum, sobre esse e alguns outros conceitos de design.
http://blog.caelum.com.br/como-nao-aprender-orientacao-a-objetos-heranca/
http://blog.caelum.com.br/effective-java-segunda-edicao/
http://blog.caelum.com.br/possibilidades-de-design-no-uso-do-seu-generic-dao/
http://blog.caelum.com.br/principios-do-codigo-solido-na-orientacao-a-objetos/

http://stackoverflow.com/questions/38820/which-class-design-is-better
http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance?answertab=votes#tab-top

Ótimos posts, confesso que tento seguir mas as vezes não vai, como é o caso que estou publicando este Tópico e pedindo auxílio.

Ainda vou tentar justificar o uso de Abstract e herança no DAO:

1 - GenericDAO é uma implementação genérica de operações que eu considero essenciais em um DAO;

2 - PessoaDAO é um DAO, assim como GenericDAO, mas contém operações Específicas como: buscaPessoasInativas();

3 - Não acho que determinar se uma entidade vai poder ser Persistida, Alterada ou Excluida é papel do DAO, mas sim da Regra de Negócio.

Exemplo:

Projeto do João: utiliza o meucore.jar como dependencia. João pede pra que se a pessoa foi cadastrado errado ele possa ser excluído.

Projeto do : utiliza o meucore.jar como dependencia.  pede pra que se a pessoa foi cadastrado errado ele não seja excluído (se quiser te passo um software muito popular que é assim).

O que vou fazer se o PessoaDAO não tem um método excluir?

É mais fácil e mais coerente eu ir no PessoaController do  e simplesmente não ter o método excluir,  que essa é uma Regra de Negócio do .
pfk66

andersonscherrer:
Rafael Guerreiro:
Algumas coisas para você ler:

Do blog da caelum, sobre esse e alguns outros conceitos de design.
http://blog.caelum.com.br/como-nao-aprender-orientacao-a-objetos-heranca/
http://blog.caelum.com.br/effective-java-segunda-edicao/
http://blog.caelum.com.br/possibilidades-de-design-no-uso-do-seu-generic-dao/
http://blog.caelum.com.br/principios-do-codigo-solido-na-orientacao-a-objetos/

http://stackoverflow.com/questions/38820/which-class-design-is-better
http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance?answertab=votes#tab-top

Ótimos posts, confesso que tento seguir mas as vezes não vai, como é o caso que estou publicando este Tópico e pedindo auxílio.

Ainda vou tentar justificar o uso de Abstract e herança no DAO:

1 - GenericDAO é uma implementação genérica de operações que eu considero essenciais em um DAO;

2 - PessoaDAO é um DAO, assim como GenericDAO, mas contém operações Específicas como: buscaPessoasInativas();

3 - Não acho que determinar se uma entidade vai poder ser Persistida, Alterada ou Excluida é papel do DAO, mas sim da Regra de Negócio.

Exemplo:

Projeto do João: utiliza o meucore.jar como dependencia. João pede pra que se a pessoa foi cadastrado errado ele possa ser excluído.

Projeto do : utiliza o meucore.jar como dependencia.  pede pra que se a pessoa foi cadastrado errado ele não seja excluído (se quiser te passo um software muito popular que é assim).

O que vou fazer se o PessoaDAO não tem um método excluir?

É mais fácil e mais coerente eu ir no PessoaController do  e simplesmente não ter o método excluir,  que essa é uma Regra de Negócio do .</blockquote>

sobre 3, toda entidade pode ser persistida. É pra isso que elas existem.

Rafael_Guerreiro

Bom, se vocês acham que isso é uma regra, entendo que vocês não trabalham com banco de dados complexos, com DBAs, com vários Schemas e até vários bancos numa mesma aplicação.

Garanto para vocês: existem entidades que não podem ser persistida, vai dar erro no banco de dados pois o seu usuário que está conectando não tem privilégio de inserção. (por determinação do DBA, por exemplo)

Segundo, o design das classes não se deve limitar ao “basta não invocar tal método”. Estamos falando de design, não de praticidade.

Justificar a herança preguiçosa não é uma saída interessante aos olhos do design.

Com a herança, você tem altíssimo acoplamento, métodos indesejados e outros problemas. É preciso ter certeza de que quer usar herança.

fabiofalci

Voce pode comentar um pouco de como sera feito o deploy dessas aplicacoes?

Nao entendi se as aplicacoes sera auto suficientes, acessando diretamente o banco de dados através das classes do core ou se o core será exposto como um servico web e entao as aplicacoes consumirao isso através de uma API.

A

fabiofalci:
Voce pode comentar um pouco de como sera feito o deploy dessas aplicacoes?

Nao entendi se as aplicacoes sera auto suficientes, acessando diretamente o banco de dados através das classes do core ou se o core será exposto como um servico web e entao as aplicacoes consumirao isso através de uma API.

As aplicações criam o hibernate.cfg no classpath e o core somente carrega as configurações, seta algumas propriedades como hibernate envers, e cria a sessionfactory, e fornece a entidade HibernateDAO por exemplo para que as aplicações utilizem ela com compoisite ou com herança para criar seus DAO específicos.

A

Bom, se vocês acham que isso é uma regra, entendo que vocês não trabalham com banco de dados complexos, com DBAs, com vários Schemas e até vários bancos numa mesma aplicação.

Garanto para vocês: existem entidades que não podem ser persistida, vai dar erro no banco de dados pois o seu usuário que está conectando não tem privilégio de inserção. (por determinação do DBA, por exemplo)

Segundo, o design das classes não se deve limitar ao “basta não invocar tal método”. Estamos falando de design, não de praticidade.

Justificar a herança preguiçosa não é uma saída interessante aos olhos do design.

Com a herança, você tem altíssimo acoplamento, métodos indesejados e outros problemas. É preciso ter certeza de que quer usar herança.

Tranquilo, caso feito as alterações ficaria parecido com:

class PessoaRepository {  
  
   //Interface DAO
   private DAO&lt;Pessoa, Long&gt; dao;
    
    @Inject
   public PessoaRepository(Session session){
		dao = new HibernateDAO&lt;Pessoa, Long&gt;(Pessoa.class, session);
   }
   //métodos crud basicos agora são delegados para a implementação da interface DAO 
   //mas  vou delegar os que eu quero
   public void gravar(Pessoa pessoa){
        dao.gravar(pessoa);
   }

   public List&lt;Pessoa&gt; buscarPessoasPorMunicipio(Muncipio municpio){  
         List&lt;Pessoa&gt; list = null;  
         //query omitida  
         return list;  
   }  
}
class EnderecoRepository{  
  
   //Interface DAO
   private DAO&lt;Endereco, Long&gt; dao;
    
    @Inject
   public EnderecoRepository(Session session){
		dao = new HibernateDAO&lt;Endereco, Long&gt;(Endereco.class, session);
   }
   //métodos crud basicos agora são delegados para a implementação da interface DAO 
}

Seria isso?

fabiofalci

andersonscherrer:
fabiofalci:
Voce pode comentar um pouco de como sera feito o deploy dessas aplicacoes?

Nao entendi se as aplicacoes sera auto suficientes, acessando diretamente o banco de dados através das classes do core ou se o core será exposto como um servico web e entao as aplicacoes consumirao isso através de uma API.

As aplicações criam o hibernate.cfg no classpath e o core somente carrega as configurações, seta algumas propriedades como hibernate envers, e cria a sessionfactory, e fornece a entidade HibernateDAO por exemplo para que as aplicações utilizem ela com compoisite ou com herança para criar seus DAO específicos.

Ao inves de exportar o core como um jar para acessar o banco de dados pq nao cria um webservice, um servico, que exportara as funcionalidades do core.
Entao as suas aplicacoes ultilizam isso como clientes, consumindo JSONs.

Assim nao se preocupando em distribuir JARs mas sim em definir uma boa API.

A


Ao inves de exportar o core como um jar para acessar o banco de dados pq nao cria um webservice, um servico, que exportara as funcionalidades do core.
Entao as suas aplicacoes ultilizam isso como clientes, consumindo JSONs.

Assim nao se preocupando em distribuir JARs mas sim em definir uma boa API.

Os outros projetos tem entidades específicas também, e consequentemente seus DAOs/Repository, e esses por sua vez utilizam a SessionFactory do core, entao ficaria meio complexo, além de aplicações desktop também utilizarem este core.

pfk66

Rafael Guerreiro:

Bom, se vocês acham que isso é uma regra, entendo que vocês não trabalham com banco de dados complexos, com DBAs, com vários Schemas e até vários bancos numa mesma aplicação.

Garanto para vocês: existem entidades que não podem ser persistida, vai dar erro no banco de dados pois o seu usuário que está conectando não tem privilégio de inserção. (por determinação do DBA, por exemplo)

Segundo, o design das classes não se deve limitar ao “basta não invocar tal método”. Estamos falando de design, não de praticidade.

Justificar a herança preguiçosa não é uma saída interessante aos olhos do design.

Com a herança, você tem altíssimo acoplamento, métodos indesejados e outros problemas. É preciso ter certeza de que quer usar herança.

Uma entidade é um fato ou informação que existe no banco de dados, então por definição ela precisa poder ser persistida. No caso das transações, quem executa é responsável por lidar com os casos onde eventualmente a transação falha. Isso geralmente é responsabilidade da camada de aplicação? Não vejo necessidade de projetar minhas entidades para estarem “cientes” disso.

pfk66

Lembrando que, mesmo quando a transação falha em alguns casos o DBA pode querer saber as entidades que o usuário não autenticado tentou salvar.

Rafael_Guerreiro

Isso mesmo!

Nem sempre, ela já existe no banco de dados. Você pode ter uma entidade para fins de consulta apenas.
Digamos que a sua aplicação utilize de dados comprados por uma terceira empresa. Esses dados são carregados numa tabela via loader. Os desenvolvedores PL/SQL fizeram uma série de lógica para tratar esses dados e entregar uma view/tabela/view materializada para você. O usuário que a sua aplicação vai usar para se conectar no banco de dados não pode fazer insert, update ou delete nessa tabela, pois ele só possui o grant de select.

Se isso, que você me disse, define uma entidade, a saída lógica seria não ter essa entidade, certo? Prefere fazer os selects e relacionamentos na mão ou usar o Hibernate e ter uma classe que representa essa view/tabela/view materializada?

pfk66:

No caso das transações, quem executa é responsável por lidar com os casos onde eventualmente a transação falha. Isso geralmente é responsabilidade da camada de aplicação? Não vejo necessidade de projetar minhas entidades para estarem “cientes” disso.

Isso é DAO, que é aonde ele estava usando a herança.

pfk66:

Lembrando que, mesmo quando a transação falha em alguns casos o DBA pode querer saber as entidades que o usuário não autenticado tentou salvar.

Quando eu falo usuário, me refiro ao usuário de conexão no banco de dados, não o usuário da aplicação.

@andersonscherrer
Sim, a diferença não é grande. Basta apenas repassar e pronto, já está adotando um padrão de projeto.

Sobre questão do JAR X WebService. Na minha opinião, não faz muita diferença prática.
É uma decisão que vem acompanhada de vários prós e contras. Pode fazer sentido você apenas compartilhar os daos e regras de negócio.

Eu, particularmente, prefiro trabalhar com WebServices. Pois é mais prático para ter aplicações web e mobile.

pfk66

Percebi agora que está falando de entidades no hibernate, eu estava falando de entidade no domain model.

A

Certo até aqui foi discutido sobre o DAO, acontece que ainda restam as outras dúvidas do começo do post,

Numa visao TOP-DOWN:

Aplicacao Cliente me envia um JSON com o objetivo de cadastrar uma Pessoa conforme o Model descrito na primeira pagina do post. Conforme:

{nome : “Zé”, enderecos:[{idmunicipio: 10, bairro: “centro”, rua: “Paraná”},{idmunicipio: 10, bairro: “morumbi”, rua: “recife”} ]}

Aqui hoje no controller eu tenho o seguinte:

//aqui eu uso o VRaptor ele deserializa pra mim o JSON
public void gravar(Pessoa pessoa){
      // validar pessoa
      // chamar o DAO ou o Service para gravar
      dao.gravar(pessoa);
}

Em conversa com o @Rafael Guerreiro

Ele sugeriu receber um DTO. Devido a alguns problemas que eu citei pra ele por exemplo controlar os dados que podem ser deserializados pelo JSON
criei algo do tipo

class PersistentPessoa{

public final String nome;
public final List<Endereco> enderecos;

public PersistentPessoa(String nome; List<Endereco> enderecos){
    this.nome = nome;
    this.enderecos = enderecos;
}

Assim eu receberia esse DTO no Controller.
Aqui tenho dúvidas, porque o Endereco também precisa ser um DTO, e outra, como foi sugerido o DTO deveria servir a apenas UMA Action do controller, então preciso ter um “TransientPessoa” que vai ser pra Atualizar pessoa?

FernandoFranzini

Suas duvidas estão em volta do conceito de DDD. Aprenda sobre antes de tomar qualquer decisão…

A

Eu já li sobre DDD, mas na prática, se não tiver ajuda de quem já mexeu com isso Comercialmente é difícil aplicar.

Eu estou a vários dias pesquisando mas não consegui transformar a Teoria em prática, e pensei que alguém pudesse passar a sua experiência aqui, como acontece na maioria das vezes, inclusive nesse tópico.

Estou em um projeto novo e tenho a oportunidade de melhorar meu código, quero deixar o mais reutilizável, e limpo. E E sei que o povo aqui ajuda muito, além disso quero deixar o post aqui pra quem precise possa vir e consultar.

Talvez eu coloque esse código no github para quem queira usá-lo mas no momento não tenho tempo pra documentar.

FernandoFranzini

DDD é não dificil de aplicar…é uma paradigma novo a aprender…toda essa discussão ai de vcs…ja esta tudo resolvido por la…

Vc vai gastar mais tempo esperando respostas dos outros, discutindo do que aprendendo DDD…
Falo isso por experiência própria…

A

FernandoFranzini:
DDD é não dificil de aplicar…é uma paradigma novo a aprender…toda essa discussão ai de vcs…ja esta tudo resolvido por la…

Vc vai gastar mais tempo esperando respostas dos outros, discutindo do que aprendendo DDD…
Falo isso por experiência própria…

Pois é, eu consegui dar uma boa melhorada no projeto pesquisando sobre arquiteturas e DDD, com certeza um ou outro vai ter opinião divergente. Mas fica aí o post para quem queira mostrar alguma coisa nova é valido.

javaflex

Eu já li sobre DDD, mas na prática, se não tiver ajuda de quem já mexeu com isso Comercialmente é difícil aplicar.

Eu estou a vários dias pesquisando mas não consegui transformar a Teoria em prática, e pensei que alguém pudesse passar a sua experiência aqui, como acontece na maioria das vezes, inclusive nesse tópico.

Estou em um projeto novo e tenho a oportunidade de melhorar meu código, quero deixar o mais reutilizável, e limpo. E E sei que o povo aqui ajuda muito, além disso quero deixar o post aqui pra quem precise possa vir e consultar.

Talvez eu coloque esse código no github para quem queira usá-lo mas no momento não tenho tempo pra documentar.
DDD à risca é muito complexo, não vale o investimento dessa complexidade técnica enquanto o cliente quer retorno para o Negócio. Parece difícil para muitos fazer o simples. Só o padrão Repository reconheço que é interessante.

A


DDD à risca é muito complexo, não vale o investimento dessa complexidade técnica enquanto o cliente quer retorno para o Negócio. Parece difícil para muitos fazer o simples. Só o padrão Repository reconheço que é interessante.

Pois é, é muito conceito teórico, do tipo: Não use herança, Não use o tal do Service, Não use modelo anêmico, SEMPRE use interface, etc… Que são conceitos de certificação, ou de desenvolvimento de frameworks, que não se aplica 100% em prática. Inclusive não encontrei NENHUM exemplo prático de DDD que compreendesse as necessidade de um CRUD que envolvesse duas Tabelas com @ManyToOne. Estou me virando mas pelos que vejo na teoria achei que alguém pudesse mostrar em prática alguma coisa que ajudasse.

javaflex

andersonscherrer:

DDD à risca é muito complexo, não vale o investimento dessa complexidade técnica enquanto o cliente quer retorno para o Negócio. Parece difícil para muitos fazer o simples. Só o padrão Repository reconheço que é interessante.

Pois é, é muito conceito teórico, do tipo: Não use herança, Não use o tal do Service, Não use modelo anêmico, SEMPRE use interface, etc… Que são conceitos de certificação, ou de desenvolvimento de frameworks, que não se aplica 100% em prática. Inclusive não encontrei NENHUM exemplo prático de DDD que compreendesse as necessidade de um CRUD que envolvesse duas Tabelas com @ManyToOne. Estou me virando mas pelos que vejo na teoria achei que alguém pudesse mostrar em prática alguma coisa que ajudasse.


Pois é, essa coisa de “interface para tudo” muitas vezes fica só num processo burocrático para atender a uma doutrina de TI, onde na prática pode nunca existir mais de uma implementação para determinado caso. Se existir a real necessidade, tudo bem. Mas essa coisa de ficar supondo “se talvez no futuro acontecer” não é uma prática ágil, o foco deve ser no horizonte real do cliente.

Não entendi que dúvida você precisa tirar inicialmente. Sobre “@ManyToOne”, isso é relacionado ao ORM Hibernate, onde deverá pesquisar sobre o mesmo, independente de outras coisas.

Sobre projeto como um todo, recentemente postaram aqui um exemplo. Veja se pode tirar algum proveito. Link direto pro src Java: https://github.com/alexlimatds/ifrn-pds-web-revenda-de-veiculos/tree/master/projetoRevendaVeiculosSpringMVC/src

pfk66

DDD deveria te ajudar a gerenciar a complexidade inerente ao software, e não criar mais complexidade.

pfk66

andersonscherrer:

DDD à risca é muito complexo, não vale o investimento dessa complexidade técnica enquanto o cliente quer retorno para o Negócio. Parece difícil para muitos fazer o simples. Só o padrão Repository reconheço que é interessante.

Pois é, é muito conceito teórico, do tipo: Não use herança, Não use o tal do Service, Não use modelo anêmico, SEMPRE use interface, etc… Que são conceitos de certificação, ou de desenvolvimento de frameworks, que não se aplica 100% em prática. Inclusive não encontrei NENHUM exemplo prático de DDD que compreendesse as necessidade de um CRUD que envolvesse duas Tabelas com @ManyToOne. Estou me virando mas pelos que vejo na teoria achei que alguém pudesse mostrar em prática alguma coisa que ajudasse.

A coisa mais importante que DDD diz é: Não compartilhe o banco de dados entre aplicações; Não use o banco de dados pra armazenar outra coisa senão objetos.

DDD não vai oferecer retorno se você vê o sistema de banco de dados como algo separado e que interage com o sistema OO.

FernandoFranzini

Me desculpem, mas vou ter q dizer…

DDD é uma estratégia…é um caminho…uma diretriz…
DDD não te força a fazer nada…vc tem que decidir com base no seu projeto…
Isso q vc estão falando não é DDD do Erik Vans…

DDD é uma estrategia de arquitetura para ser simples, rápido e fácil…o ser OO…

Infelizmente não tem como discutir DDD dentro de um contexto no forum…seria algo muito demorado…

Mas fica a dica ai…
T+

javaflex

FernandoFranzini:
Me desculpem, mas vou ter q dizer…

DDD é uma estratégia…é um caminho…uma diretriz…
DDD não te força a fazer nada…vc tem que decidir com base no seu projeto…
Isso q vc estão falando não é DDD do Erik Vans…

DDD é uma estrategia de arquitetura para ser simples, rápido e fácil…o ser OO…

Infelizmente não tem como discutir DDD dentro de um contexto no forum…seria algo muito demorado…

Mas fica a dica ai…
T+


Nao acho isso simples, por mais que nao force algo…

Foco no negócio, simplicidade, manutenibilidade, etc, são coisas óbvias para um time entrosado com nível de experiência média plena. Adotar algo para “ser OO…” é pensar mais em TI do que atender o Negocio. Prefiro não adotar soluções para problemas que não existem. Quem geralmente precisa de diretrizes são fábricas de softwares, lugares com alta rotatividade ou equipe pouco experiente, ai sim concordo que o DDD deve fazer sentido.

pfk66

Se você tem uma aplicação simples não precisa de DDD, usa Smart UI.

Mas até onde sei, DDD e SmartUI podem ser OO do mesmo jeito.

A

Particularmente, acho que sua dúvida tem muito mais a ver com arquitetura do que com DDD.

Eu recomendaria muito ir para a opção de compartilhar essa api via web service ao invés de jar.

Alguns dos problemas que vejo com jars são:

  • tem que fazer deploy de todos seus clientes quando há uma mudança no core
  • tem que “carregar” configurações do core para seu cliente (endereço do db, urls)
  • aumenta risco de conflito de versões entre aplicativos (quero usar lib A 2.0 no client web, mas meu core só funciona com A 1.0)

Não sei quanto desses problemas seriam reais no seu caso, mas eu prefiro nunca compartilhar jars.

javaflex

pfk66:
javaflex:

Nao acho isso simples, por mais que nao force algo…

Foco no negócio, simplicidade, manutenibilidade, etc, são coisas óbvias para um time entrosado com nível de experiência média plena. Adotar algo para “ser OO…” é pensar mais em TI do que atender o Negocio. Prefiro não adotar soluções para problemas que não existem. Quem geralmente precisa de diretrizes são fábricas de softwares, lugares com alta rotatividade ou equipe pouco experiente, ai sim concordo que o DDD deve fazer sentido.

Se você tem uma aplicação simples não precisa de DDD, usa Smart UI.


Me referi sobre “simples” em relação a arquitetura e não a aplicação a nível de processos de Negócio. Não é porque a aplicação é complexa que precisamos de DDD, nem se a aplicação for simples tem que chegar ao extremo oposto de seguir “Smart UI”, como se fosse 8 ou 80. Mas enfim, cada equipe escolhe o que precisa ou não para atender as demandas no dia a dia.

A

AbelBueno:
Particularmente, acho que sua dúvida tem muito mais a ver com arquitetura do que com DDD.

Eu recomendaria muito ir para a opção de compartilhar essa api via web service ao invés de jar.

Alguns dos problemas que vejo com jars são:

  • tem que fazer deploy de todos seus clientes quando há uma mudança no core
  • tem que “carregar” configurações do core para seu cliente (endereço do db, urls)
  • aumenta risco de conflito de versões entre aplicativos (quero usar lib A 2.0 no client web, mas meu core só funciona com A 1.0)

Não sei quanto desses problemas seriam reais no seu caso, mas eu prefiro nunca compartilhar jars.

Minha dúvida na verdade era Melhorar o código ou a relação entre as camadas e actions. Por ex. agora estou sem a camada Service, recebo DTO no controller, chamo o DAO/Repository e este por sua vez cria as Entidades através dos DTOs e persiste ou atualiza etc, antes eu tinha o Service no meio do caminho, e também não recebia DTO no controller, recebia direto a Entity.
Sobre compartilhar .jar até agora está indo bem, é meio que “viajem” da minha parte, mas já não estou mais precisando copiar código em cada projeto novo.
E trabalhando direitinho com o maven, estou conseguindo me virar, por enquanto não teve problema de versão de biblioteca.

Criado 28 de maio de 2015
Ultima resposta 9 de jun. de 2015
Respostas 37
Participantes 8