Submarino.com.br

Domain Store

Objetivo

Prover persistência para objetos de domínio de forma unificada e centralizada.

Propósito

O padrão Domain Store foi introduzido no ambiente JEE [1]. para simplificar e desacoplar a interacção das aplicações Java com o ambiente de persistência de forma que isso pudesse ser apresentado como um serviço pelo Servidor de Aplicação e remover do programador a responsabilidade de manipular a tecnologia de persistência directamente ou pelo uso de outros padrões como o DAO. Paralelamente o padrão foi tornado popular pelo Hibernate e depois pelo JPA.

Problema

Aplicações corporativas frequentemente necessitam persistir informações. Quando no design da aplicação existe uma camada de domínio, é útil poder realizar esta persistência de forma transparente. Esta transparência está relacionada não ao local para onde a persistência é realizada (banco de dados, arquivo, etc... ) mas com as relações entre as instâncias dos objectos de domínio.

Em um design orientado a domínio, é necessário procurar instâncias de entidades de domínio que são contidas ou contêm outras instâncias de entidades do domínio, os chamados Agregados. A definição de uma camada de domínio orientada a agregados é inerentemente diferente de uma camada de negócio que simplesmente manipula dados. Em uma camada de domínio os dados contêm relações que são controladas por eles mesmos e não pelo objectos de serviço. O tratamento destas relações nem sempre é trivial e é ai que entra o padrão DomainStore

Solução

A solução passa por abstrair todas as operações relacionadas a persistência e encapsular essas operações atrás de uma única abstracção - o Domain Store. O Domain Store é definido por um único contrato, que pode ou não ser uma interface. Este contrato é agnóstico à entidade que está em jogo o que permite que uma única instância do DomainStore consiga responder por todas as entidades de um domínio.

Implementação

Não existe uma forma especifica de como implementar um Domain Store. Teoricamente seria possível implementar um DomainStore especifico para o domínio da aplicação, mas na prática existem frameworks para cuidar de domínios de forma genérica (Hibernate, por exemplo). Estas implementações normalmente passam por abstrair de alguma forma os meta-dados que representam o modelo de domínio e prover as operações CRUD (Cread, Retrive, Update, Delete) com base nesse modelo do domínio. Em particular a maioria das implementações do padrão DomainStore se utilizam do conceito de uma sessão de trabalho (padrão Unit of Work).

Podemos separar a implementação do padrão DomainStore em duas partes. A primeira parte é a interface de uso. Aquela com que o sistema interage para realizar as operações de pesquisa e persistência. A segunda parte é a configuração. A forma como é informado à implementação como a pesquisa e como a persistência tem que ser feita. Normalmente esta segunda parte é feita através de meta-dados. Ou seja, o programador descreve o modelo e a implementação já sabe como realizar as operações. Isto pode ser feito programaticamente através de uma API especifica, por anotações ou por uso de arquivos de configuração (em XML, por exemplo). Historicamente os frameworks de DomainStore começaram por adotar os arquivos XML , depois as anotações e mais recentemente a configuração programática. A configuração programática é importante para que estes frameworks possam ser integrados como componentes em frameworks maiores.

A abstracção do Domain Store funciona em cima do conceito de Store (Loja). Você pode adicionar ou remover um elemento da loja. Você pode pesquisar por uma instância, ou por um conjunto de instâncias. E também você pode atualizar os dados correspondentes a uma instância. Porque as instâncias são de objectos de domínio e não quaisquer objectos, estes objectos têm que ter a propriedade de Identidade. A identidade de cada instância tem que ser visível ao mecanismo do DomainStore, embora não seja - normalmente - necessário que seja visível ao resto da aplicação. O Domain Store irá usar a identidade para processar as buscas e as relações entre as entidades.

A primeira parte da implementação do DomainStore, passa por uma interface simples e genérica que pode ser utilizada para trabalhar com qualquer tipo de entidade.

			public interface DomainStore {
			  
				  public <T> T save(T obj); // adiciona ou atualiza
				  public <T> T delete(T obj); // remove
				  public <T> QueryResult<T> find(Query<T> query}; //pesquisa
				  
			}
			
Código 1:

Repare que a interface não é genérica, mas os métodos são. Na realidade os métodos genéricos servem apenas para consolidar uma tipagem forte para a API, pois na prática estaremos usando qualquer objeto. Esta interface é usada para manipular e encontrar os objetos na loja. Outros métodos adicionais podem ser utilizados, e normalmente os criadores de frameworks de DomainStore provêm vários métodos utilitários a mais. O que realmente interessa é que exista a possibilidade de incluir e modificar uma instância (método save), remover a instância (delete) e pesquisar uma conjunto de instâncias ( find). O método find é particularmente importante pois a pesquisa a ser realizada é definida utilizando um objecto de pesquisa (padrão QueryObject) e não definindo vários métodos especiais. É esta caracteristica que distingue fortemente o padrão DomainStore de outros padrões relacionados a persistência como DAO.

A abstracção do DomainStore não trabalha explicitamente com o conceito de banco de dados. A implementação pode delegar ou não a um banco de dados. Embora comum, isso não é necessário para a definição do DomainStore. Internamente uma implementação de DomainStore usará outros padrões relacionados com a tecnologia de persistência, tais como o Strategy ou o DAO. A implementação de diferentes estratégias, permitem que um só DomainStore possa persistir seus dados em locais e tecnologias diferentes. Normalmente as implementações de frameworks de DomainStore não focam este cenário,pois é raro na prática, mas é teoricamente possível. Quando você realmente precisar fazer isto será obrigado a diferenciar a sua abstracção do seu DomainStore, dos frameworks e tecnologias utilizados na sua implementação. O padrão Strategy pode ser utilizado para chavear entre as tecnologias necessárias a cada entidade,contudo, será necessário coordenar todas essas estratégias de forma que para o exterior pareça que as instâncias estão em um único local.

Discussão

É comum existirem designs de aplicações onde o DomainStore ( por exemplo, o Hibernate) é chamado de dentro de objetos DAO específicos para cada entidade. Isto é errado. Ao usar o DomainStore não estamos apenas fazendo de persistência, estamos fazendo uso de modelagem de dominio, e embora possamos persistir os dados em outro local fisico, ou usando outra tecnologia, não iremos alterar o fato do nosso modelo ser orientado ao dominio. Por isso não faz sentido falarmos em substituir o DomainStore por outro padrão, mas sim modificar o local onde o DomainStore guarda os dados. O DomainStore já é genérico de forma a abstrair qualquer entidade.

O padrão DomainStore aceita um objecto de pesquisa para fornecer instâncias ou conjuntos de instâncias. Estes objectos de pesquisa precisam ser construídos. É recomendado que o controle sobre a criação de objetos de pesquisa não seja espalhada pelo sistema. Para isso é sensato e eficaz utilizar o padrão Repository para encapsular as regras de negócio que levam ao uso de determinada query. Inclusive à montagem dinâmica da query com base em regras de negócio. O padrão Repository define objectos que pertencem à camada de domínio Assim sendo, o DomainStore só é chamado por objectos da camada de Domínio sendo principalmente chamado por objectos Repository para pesquisas e Serviços para uso dos métodos de modificação da loja.

Padrões relacionados

O DomainStore está relacionado ao padrão DAO pois foi criado para abstrair e unificar o uso do que antes poderia ser um conjunto enorme de famílias de DAO. Contudo, internamente o DomainStore ainda precisa do padrão DAO para abstrair a tecnologia de persistência e funcionar como Strategy para diferentes tecnologias de persistência.

O DomainStore também está relacionado ao padrão Repository. O padrão Repository é encarregue de conhecer quais e como são montadas as queries que o DomainStore executa. A lógica de negócio de uma query está nela mesma e não na forma como é executada. Então o Repository e o DomainStore ajudam a separar as responsabilidades. O primeiro determina qual é a query que interessa e o DomainStore determina como ela é realizada. Esta parceria é bem diferente do uso do padrão DAO em que o DAO define não apenas como é feita a pesquisa, mas qual é a pesquisa a ser realizada.

As queries em si mesmas são definidas usando o padrão QueryObject e a implementação do DomainStore atua como um Interpreter para esse QueryObject. Em muitas implementações do padrão DomainStore (como o Hibernate ou o JPA) é ainda usado o conceito de Unit Of Work para criar o conceito de sessão. O uso deste padrão cria uma maior complexidade , mas obriga o programador a pensar em termos de objectos que estão em uma loja (explicitada na sessão) e não no banco de dados, ajudando a fortalecer o padrão DomainStore. Contudo, na prática é isto que cria os maiores problemas de entendimento de como usar os frameworks que implementam este padrão.

Referências

[1] Core JEE Patterns 2nd Edition

URL: Core JEE Patterns 2nd Edition http://www.corej2eepatterns.com/Patterns2ndEd/DomainStore.htm