Consegui evitar os VOs e BOs?

Entao… ate onde eu li, eu so achei isso relacionado ao assunto, a minha tradução é pessima.

É necessário um complexo particionamento do programa em camadas. Desenvolver uma concepção dentro de cada camada que é coerente e que depende apenas das camadas inferiores. seguir padrões arquitectónico padrão para fornecer um engate avulso para as camadas acima. Concentrar todo o código relacionado ao modelo do domínio em uma camada e isolá-lo da relação de usuário, da aplicação, e do código da infraestrutura. Objetos de domínio, sem resposabilidade de se mostrar, armazenando neles mesmos, administrando tarefas de aplicativos e assim por diante, podem estar focados em expressar o modelo do domínio. Isso permite o modelo envolvido ser rico e claro o bastante para capturar a essencia do conhecimento do negócio e colocoar isso para trabalhar

Segue abaixo o texto original

Therefore, partition a complex program into LAYERS. Develop a design within each LAYER that is cohesive and that depends only on the layers below. Follow standard architectural patterns to provide loose coupling to the layers above. Concentrate all the code related to the domain model in one layer and isolate it from the user interface, application, and infrastructure code. The domain objects, free of the responsibility of displaying themselves, storing themselves, managing application tasks, and so forth, can be focused on expressing the domain model. This allows a model to evolve to be rich enough and clear enough to capture essential business knowledge and put it to work

Portanto, o que vc falou parece ser correto, mas eu sinceramente tenho duvidas quanto a isso, o mais importante é que se essa abordagem estiver correta talves nao precisamos chamar o servico da forma que eu demonstrei.

Eu fiz uma pergunta no site aonde o livro esta disponivel para download para ver se eles deixam publicar as partes mais importantes do livro. Eu tenho varias anotações para publicar, mas vou esperar a resposta deles.

Observações:
Eu acho educado não so mostrar o texto original mas tb o que eu entendi do texto e por isso coloquei a tradução, eu espero que isso seja uma pratica comum pois esse é um forum em portugues e existem pessoas que lem esses textos e que as vezes nao sabem ler em ingles ou entende o texto de uma outra forma.

Quanto aos services concordo com você. Eu entendi o service no DDD como algo diferente do que tenho visto por aí. Tenho visto o pessoal dar o nome de Service para as fachadas que separam controle e domínio. Sinceramente entendo que não seja este o objetivo do service. Pelo que entendi usamos o service para agrupar operações mais complexas que exigem uma manipulação de entidades não relacionadas entre si, por exemplo. Acho que colocamos no service aqueles métodos que não combinariam se ficassem em uma entidade… :mrgreen: Será que é isso mesmo?

Exemplificando com código… usando os exemplos que postei anteriormente o controle ficaria assim:

[code]protected ModelAndView onSubmit(Object command) throws ServletException {
Owner owner = (Owner) command;
// delegate the insert to the Business layer

	getClinic().storeOwner(owner);

	return new ModelAndView(getSuccessView(), "owner", owner);
}[/code]

e o service que eu tinha postado:

public void storeOwner(Owner owner) { owner.save(); }

O método storeOwner() tem só uma linha! Não seria melhor eu apagar o método storeOwner() do meu service e chamar direto o owner.save() no meu controle?

[code]protected ModelAndView onSubmit(Object command) throws ServletException {
Owner owner = (Owner) command;
// delegate the insert to the Business layer

	owner.save();

	return new ModelAndView(getSuccessView(), "owner", owner);
}[/code]

O que eu não sei é se fazendo owner.save() dentro do meu controle quebraria alguma regra do DDD ou se o DDD espera isso mesmo! :roll:

Aí que está: existem Services em diversos níveis mas a maioria reside nessa borda.

Services são Façades de negócio, eles encapsulam lógica de negócio que envolve interações complexas. A únida diferença entre um Service e um Façade é que como tudo em DDD um Service tem que ter uma ligação de 1-para-1 com um conceito de negócios.

[quote=Thiago Senna]
O que eu não sei é se fazendo owner.save() dentro do meu controle quebraria alguma regra do DDD ou se o DDD espera isso mesmo! :roll: [/quote]

Em Java eu diria que sim porque não há um meio feliz de se ter este método sem implementá-lo diretamente no objeto de negócio ou fazê-lo parte de alguma infra-estrutura (deixandod e ser um POJO). Em plataformas mais dinâmicas como Ruby não, já que Persistência é um conceito a parte e se vai ser implementado via AR ou DataMapper não interfere no design da classe de negócios (já que o framework ou engine AOP poderia colcoar o método save() dinamicamente no objeto em runtime).

O que você tem que rpestar atenção é que um objeto de negócios chamar um método save(), seja em que plataforma for, não é DDD visto que eles (objetos de negócio) só se preocupam com o que faz parte do domínio (logo seu Service tem problemas).

[quote=Thiago Senna]
O que eu não sei é se fazendo owner.save() dentro do meu controle quebraria alguma regra do DDD ou se o DDD espera isso mesmo! :roll: [/quote]
Muitas duvidas, a imagem da a enteder que vc pode invocar.

Quick DDD pag 31
Um exemplo típico de interação da aplicação, domínio e infraestrutura podiam funcionar dessa forma: O usuário deseja uma rotas de vôo, e pergunta ao serviço na camada de aplicação como fazer isso. Uma parte da aplicação busca os objetos relevantes do domínio da infraestrutura e invoca métodos relevantes para fazer isso ao verificar margens de segurança a outros vôos já registrados. Uma vez que os objetos do domínio fizeram todas as verificações e atualizaram seu status para ?decidido?, o serviço da aplicação persiste os objetos para a infraestrutura.

Observações:
É muito importante ter um linguajar comum, eu entendo que o que vc chama de controle seja a segunda camada(application).



(…) Concentrate all the code related to the domain model in one layer and isolate it from the user interface, application, and infrastructure code. The domain objects, free of the responsibility of displaying themselves, storing themselves, managing application tasks, and so forth, can be focused on expressing the domain model. This allows a model to evolve to be rich enough and clear enough to capture essential business knowledge and put it to work

Portanto, o que vc falou parece ser correto, mas eu sinceramente tenho duvidas quanto a isso, o mais importante é que se essa abordagem estiver correta talves nao precisamos chamar o servico da forma que eu demonstrei.
[/quote]

Destaco a seguinte frase da citação

Para mim esta frase é muito clara e significa que:

  1. Objectos de dominio não podem ter funções que dependam ou se destinem a UI ou IO. (“displaying themselves”)
  2. Objetos de domínio não podem seguir o padrão ActiveRecord (“save themselves”) , nem nada semelhante. A responsabilidade de guardar e reobter os objetos é exclusivamente do repositório (por isso ele existe).
  3. Serviços de domínio (digo de dominio para diferenciar dos de aplicação e outros) não podem depender de tecnologias (" managing application tasks"). E por isso não devem ser implementados dentro de um servlet ou coisas semelhante.

Os controladores (a aplicação) podem enxergar os objetos de domínio, mas as regras (lógicas) de dominio não podem ficar nos controladores.
Se a regra é muito complexa e um só objeto de dominio não é suficiente, precisamos de um serviço. Respondendo ao Thiago, sim, é para isto que servem os serviços de dominio.

Ai entra a questão de diferenciar “logica de dominio” de “logica de negocio” . Se o objeto pessoa me permite saber a data de nascimento da pessoa, a camada de aplicação pode ter um mecanismo que use essa capacidade , algo do tipo

print "olá"
if (person.hasborn(Date.today())){
   print "Parabéns pelo seu  aniversário"
}

Ora , isto é o uso do dominio pela aplicação. É um exemplo muito simples, e tlv isso atrapalhe. A questão é que consultar se a pessoa nasceu hoje é um coisa que a aplicação faz, mas a logica que responde a isso , está no objeto do dominio.
Moral da historia , se a logica pertence ao domínio, ela deve apenas existir nos objectos de dominio (VO, Entidades, Serviços) e nunca em outras camadas. Se a logica é de uso do domínio ela fica fora do dominio, em qq outra camada (espera-se que na de aplicação, mas pode ser usada na de apresentação eventualmente)

O entrave fundamental que parece permear este tópico é dar exemplos de DDD usando persistência. Embora persistencia seja um dominio também, ele é muito especial. Se misturarmos as duas coisas vamos acabando resolvendo que a entidades podem ser ActiveRecords e que o Repositorio não serve para nada (exatamente o contrário do que é afirmado pela DDD e frase citada deixa bem claro). Um bom exemplo para entender a diferença é dar uma olhada na TimeAndMoney API. Embora a Joda Time seja tecnicamente superior, a TimeAndMoney demonstra melhor os conceitos de DDD. Não vão ver la código de persistência.

E quando as dependências das entidades (a implementação do repositório por exemplo) são injetadas via ID usando AOP? Neste caso, mesmo sendo uma aplicação java as suas entidades deixariam de ser um POJO? Posso estar errado, mas vejo esta solução como algo parecido com o que acontece com linguagens dinâmicas, só não tão bonito! rsrs…

Essa parte me deixou confuso. Se eu quero que após uma determinada operação o estado da entidade seja persistido não posso chamar o método entidade.save() e sim o repository.add(entidade)? Ou melhor ainda, a camada de negócios manipula o estado da entidade e no final a camada de aplicação se responsabiliza por delegar a persistência da entidade para a camada de infraestrutura (chamando entidade.save(), por exemplo)?

[quote=ronildobraga]Observações:
É muito importante ter um linguajar comum, eu entendo que o que vc chama de controle seja a segunda camada(application). [/quote]
Sim sim! O que chamo de controle seria a camada de aplicação. Valeu!

Ótimo! Também penso isso por que vejo muito isso no Grails. Agora o que pega é o detalhe que o Shoes citou sobre java x linguagens dinâmicas. Mas acho que hoje vale a pena (dependendo da aplicação) utilizar uma infraestrutura similar ao que vemos nas linguagens dinâmicas.

Não só persistência, mas os CRUD’s em especial complicam nossa vida. Tomara que este tópico não se transforme em ActiveRecord X Repositório. Este trecho que você argumentou deixou claro que DDD != Active Record! :wink:

[quote=sergiotaborda]Destaco a seguinte frase da citação

The domain objects, free of the responsibility of displaying themselves, storing themselves, managing application tasks, and so forth, can be focused on expressing the domain model.

Os objetos de domínio , livres da responsabilidade de se apresentarem a si próprios , guardar a si próprios, gerenciar tarefas da aplicação, e assim por diante, podem se focar em expressar o modelo do domínio.

Para mim esta frase é muito clara e significa que:

  1. Objectos de dominio não podem ter funções que dependam ou se destinem a UI ou IO. (“displaying themselves”)
  2. Objetos de domínio não podem seguir o padrão ActiveRecord (“save themselves”) , nem nada semelhante. A responsabilidade de guardar e reobter os objetos é exclusivamente do repositório (por isso ele existe).
  3. Serviços de domínio (digo de dominio para diferenciar dos de aplicação e outros) não podem depender de tecnologias (" managing application tasks"). E por isso não devem ser implementados dentro de um servlet ou coisas semelhante. [/quote]

Vou tentar exemplificar com código o que seria um uso adequado de repositório e entidade na camada de aplicação:

Um exemplo (só o C do CRUD) para salvar um aluno:

[code]protected ModelAndView onSubmit(Object command) throws ServletException {
Aluno aluno = (Aluno) command;
// delegate the insert to the Business layer

	alunoRepository.store(aluno);

	return new ModelAndView(getSuccessView(), "aluno", aluno);
}[/code]

Agora um exemplo que possui lógica de negócio e esta reside na entidade Turma. Ela deve retornar os alunos com nota abaixo da média:

na camada de aplicação

[code]protected ModelAndView onSubmit(Object command) throws ServletException {
Turma turma = (Turma) command;
// delegate the insert to the Business layer

	List<Aluno> alunos = turma.getAlunosComNotasAbaixoDaMedia();

	return new ModelAndView(getSuccessView(), "alunos", alunos);
}[/code]

A entidade turma por sua vez consulta o repositório:

[code]public class Turma {

private AlunoRepository alunoRepository;

public Lis getAlunosComNotasAbaixoDaMedia() {
List todos = alunoRepository.getAll();
List alunosNoVermelho = new ArrayList();

for (Aluno aluno: todos) {
    if (aluno.getNota() < 5) {
        alunosNoVermelho.add(aluno);
    }
}

return alunosNoVermelho;

}

}[/code]

Resumindo: Em geral na camada de aplicação usamos o repository para operações do tipo CRUD (ou outras operações muito simples), no entanto, quando conveniente para isolar a lógica de negócio na entidade podemos acessar o repositorio de dentro da entidade. Estamos avançando? :mrgreen:

Isso depende muito da interpretação de cada pessoa, eu particularmente acho que sim, mesmo que as vezes a gente entre em contradição eu espero que no final todos tenham entendido alguma coisa.

Porem algumas pessoas acham que isso aqui é tudo desentendimento e que so falamos besteira, e ainda escreve artigos http://blog.fragmental.com.br/2007/06/22/cuidado-com-domain-driven-design/ falando sobre mim com relação a esse post e depois tem a coragem de vir aqui e tb dar a sua propria opiniao como se esse fosse outro post e ainda ignora tudo que eu falo.

Como eu tinha dito, eu traduzo os texto nao so por educação, mas tb para estabeler um linguagem comum entre a gente assim como o proprio livro do DDD aconselha

Não só persistência, mas os CRUD’s em especial complicam nossa vida.(…)
[/quote]

Se entendermos que CRUD é uma operação de manutenção/população do repositorio, então CRUD é apenas uma camada em cima do repositório.
Mais ou menos assim


@Façade // este não é um serviço do mesmo dominio dos objetos que persiste
public CRUDService { 

        public  store (EntityTO obj){ //EntityTO   é uma interface
               Entity e = Assembler.desasemble(obj); // transforma em entidade
               Repository.store(e); // stre inclui update e insert
        }

// método generico para fazer queries
       public  T retrive(Class<T> classe, Query q){
               Reporitory.retrive(classe,q);
        }

// método utilitário para fazer queries
        public  T retrive(Class<T> classe, Object id){
               Reporitory.retrive(classe,Query.idQuery(id));
        }
}

O objeto Query serve para isolar a pesquisa da tecnlogia de persistencia subjacente.

Este serviço é um objeto da camada de aplicação que fica acima da de dominio. O principal detalhe que falta aqui é a validação antes de guardar. A qual deveria , a principio , ser responsabilidade do dominio e podemos pensar que está no repositorio (só para simplificar)

Quanto a mim o código seria mais independente (não necessáriamene melhor) desta forma:

protected ModelAndView onSubmit(Object command) throws ServletException {


  		AlunoTO alunoTo = (AlunoTO) command; // purismo de não usar entidades na camada de apresentação

  		// delegate the insert to the Persistence layer
  
  		CRUDService s  = ...
                s.store(aluno);
  
  		return new ModelAndView(getSuccessView(), "aluno", alunoTo);
  	}

No fim, o repositorio usa um DAO interno para persistir as alterações.
Poderiamos penar que o façade de crud trabalha directamente sobre o DAO sem passar pelo repositorio. É como se a carga das instancias das entidades fosse “exterior” ao repositório. Assim poderiamos usar JPA em cima dos TO e deixar as entidades puras, sem referencia a nenhuma tecnologia. Por outro lado teriamos que encontrar forma de validar esses TO durante a pesistencia. Aqui, poderiamos entender que a validação fica em outras classes do dominio (que eu chamo de validadores, mas a DDD chama de Specification … e no fim não é bem a mesma coisa) - os validadores. Os validadores seriam chamados pela aplicação antes do .CRUD algo como

protected ModelAndView onSubmit(Object command) throws ServletException {


  		AlunoTO alunoTo = (AlunoTO) command; // purismo de não usar entidades na camada de apresentação

  		
                 AlunoValidator v = new AlunoValidator ();
                ValidationResult r = v.validate(alunoTo);

               if (!r.isValid()){
                   // poderiamos passar o r, que contém as razões da invalidação
                  return new ModelAndView(getInvalidView(), "aluno", alunoTo);

               }

// delegate the insert to the Persistence layer
  		CRUDService s  = ...
                s.store(aluno);
  
  		return new ModelAndView(getSuccessView(), "aluno", alunoTo);
  	}

Quanto mais independente a camada de dominio for da camada de aplicação e ambas da de persistencia mais transformações serão necessárias e mais objetos serão necessários (como Query).
Isto é um bocado chato. No fim das contas poderiamos usar as entidades anotadas com JPA. Só que, isso violaria o purismo de DDD e é uma escolha de implementação. Entendido isso, o bom é ter independência total para diminuir o acoplamento das camadas, mas isso implica em uma infraestrutura maior.

O meu ponto é que não se deveria confundir o serviço de CRUD com o Repositório. Eles serão tão mais confundiveis quanto mais acopladas tiverem as camadas. Por exemplo, sem TO, as ppr entidades navegam entre as camadas. Se não ha TO não ha Assembler e portanto o papel do seriço CRUD é futil. Mas se fizermos isso estamos usando um pseudo-DDD. No frigir dos ovos isso pode ser suficiente para alguma aplicação, mas concerteza não é recomendado acoplar as camadas assim.